如何使用自定义ArrayAdapter跟踪自定义ListView中的项目检查?

时间:2013-03-22 08:22:36

标签: android checkbox android-listview android-arrayadapter

我的堆栈确实溢出,我的意思是目前我的大脑无法想出解决下面问题的方法(虽然我经历了多天的试错)。我想做的就是像(http://asset0.cbsistatic.com/cnwk.1d/i/tim/2010/11/18/Foreman_11654166_1073_com.probosoft.masscontactsdelete0_257x386.png

这样的删除目的

我有一个list-view-item的布局,如下所示(log_view.xml):

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:padding="5dp" >

    <TextView
        android:id="@+id/date_view"
        android:gravity="top|left"
        android:textStyle="bold"

        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_alignParentLeft="true" />

    <TextView
        android:id="@+id/value_view"
        android:gravity="top|left"
        android:layout_width="match_parent"
        android:layout_height="match_parent"

        android:layout_below="@+id/date_view"
        android:layout_alignParentLeft="true" />

     <CheckBox 
        android:id="@+id/del_box"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentRight="true"
        android:layout_centerVertical="true"
        android:layout_marginRight="5dp"
        android:visibility="gone"

        android:focusable="false"
    android:focusableInTouchMode="false" />

</RelativeLayout>

这是我的自定义适配器:

class LogViewAdapter extends ArrayAdapter<Log>  {   
    public ArrayList<Boolean> checkList;
    private int layoutResourceId;
    private List<Log> logList;

    Context context;

    public LogViewAdapter(Context context, int layoutResourceId, List<Log> data) {
        super(context, R.layout.log_view, data);

        this.layoutResourceId = layoutResourceId;
        this.logList = data;
        this.context = context;

        checkList = new ArrayList<Boolean>();
        for (int i = 0; i < logList.size(); i ++)   {
            checkList.add(false);
        }
    }

    @Override
    public View getView(final int position, View convertView, ViewGroup parent) {
        LogHolder logholder = null;

        // Unidentified view            
        if(convertView == null) {
            LayoutInflater inflater = ((Activity)context).getLayoutInflater();
            convertView = inflater.inflate(layoutResourceId, parent, false);

            // Create a new holder
            logholder = new LogHolder();

            logholder.del_box = (CheckBox)convertView.findViewById(R.id.del_box);
            logholder.del_box.setChecked(false);

            final int iFinal = position;
            logholder.del_box.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
                public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
                    checkList.set(iFinal, buttonView.isChecked());
                }
            });

            logholder.date_view = (TextView)convertView.findViewById(R.id.date_view);
            logholder.value_view = (TextView)convertView.findViewById(R.id.value_view);

            convertView.setTag(logholder);
        }

        // Identified view
        else    {
            logholder = (LogHolder) convertView.getTag();
        }

        if (null != logList)    {
            if (null == checkList.get(position))    {
                android.util.Log.e("getView", "Checklist null at " + position);
            }

            //logholder.del_box.setChecked((boolean)checkList.get(position));
            logholder.date_view.setText(logList.get(position).date);
            logholder.value_view.setText(logList.get(position).value);
        }

        android.util.Log.e("getView", " at " + position + ", value = " + logholder.value_view.getText().toString());
        return convertView;
    }

    static class LogHolder  {
        TextView date_view;
        TextView value_view;
        CheckBox del_box;
    }
}

这是我的活动:

public class LoggingActivity extends Activity   {

    //private EditText edt_name;
    //private EditText edt_value;
    private List<Log> logList;
    private LogViewAdapter lw_adapter;
    private ListView listView;


    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.log_list);
        //setContentView(android.R.layout.simple_list_item_multiple_choice);

        logList = loadLog();
        listView = (ListView)findViewById(R.id.log_list);

        lw_adapter = new LogViewAdapter(this, R.layout.log_view, logList);
        //lw_adapter = new LogViewAdapter(this, android.R.layout.simple_list_item_multiple_choice, logList);

        listView.setAdapter(lw_adapter);
    }

    /** implements for the MENU soft-key. Android 2.3.x */
    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        MenuInflater inflater = getMenuInflater();
        inflater.inflate(R.layout.log_menu, menu);

        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // IMPORTANT: listView.getChildAt(index) will only return the
        // VISIBLE views in our current screen
        if (null == listView)   {
            android.util.Log.e("onOptionsItemSelected", "list view null");
            return true;
        }

        for (int i = 0; i < listView.getChildCount(); i++) {
            if (null == listView.getChildAt(i)) continue;

            CheckBox cb = (CheckBox) listView.getChildAt(i).findViewById(R.id.del_box);
            if (null == cb) {
                android.util.Log.e("CB", "CheckBox at i = " + i + " null");
                return true;
            }

            final int iFinal = i + listView.getFirstVisiblePosition();
            cb.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
                public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
                    listView.setItemChecked(iFinal, buttonView.isChecked());
                    lw_adapter.checkList.set(iFinal, buttonView.isChecked());
                }
            });

            SparseBooleanArray selectedItems = listView.getCheckedItemPositions();

            for (int j = 0; j < selectedItems.size(); j++) {
                if (selectedItems.get(j)) {
                    android.util.Log.e("CHECKED", "Row "+ j + ", value = " + logList.get(j).value);
                }

                else    {
                    android.util.Log.e("CHECKED", "Row "+ j + " not checked");
                }
            }

            cb.setVisibility(View.VISIBLE);
            cb.setEnabled(true);
        }

        File folder = new File(Environment.getExternalStorageDirectory(), "50802566/logs");

        // Handle item selection
        switch (item.getItemId()) {
            case R.id.log_sort:
                Collections.sort(logList, Log.COMPARE_BY_VALUE);
                lw_adapter.notifyDataSetChanged();

                return true;
            case R.id.log_del:
                for (int i = 0; i < logList.size(); i++) {
                    if (null == lw_adapter.checkList.get(i))    {
                        android.util.Log.e("DEL", "checklist["+ i + "] = null");
                        continue;
                    }

                    if (true == lw_adapter.checkList.get(i)) {
                        // Delete correlative xml file
                        Date date = null;
                        try {
                            date = new SimpleDateFormat("dd/MM/yyyy - HH:mm:ss").parse(logList.get(i).date);
                        } catch (ParseException e) {
                            e.printStackTrace();
                        }

                        String filename = new SimpleDateFormat("dd_MM_yyyy - HH_mm_ss").format(date) + ".xml";
                        File toDelete = new File(folder, filename);
                        if (!toDelete.delete()) {
                            android.util.Log.e("DEL", "File " + filename + ": not deleted or not existed");
                        }

                        // Update the UI
                        //lw_adapter.remove(logList.get(i));
                        //lw_adapter.checkList.remove(i);

                        logList.set(i, null);
                        lw_adapter.checkList.set(i, null);
                        android.util.Log.e("DEL", "Deleted " + i + ", size now = " + logList.size());
                    }  
                }

                for (int i = 0; i < logList.size(); i ++)   {
                    if (null == logList.get(i)) {
                        logList.remove(i);
                        lw_adapter.checkList.remove(i);
                    }
                }

                lw_adapter.notifyDataSetChanged();

                // Refresh the checklist
                for (int i = 0; i < lw_adapter.checkList.size(); i ++)  {
                    lw_adapter.checkList.set(i, false);
                }

                for (int i = 0; i < listView.getChildCount(); i++) {
                    if (null == listView.getChildAt(i)) continue;
                    CheckBox cb = (CheckBox) listView.getChildAt(i).findViewById(R.id.del_box);
                    cb.setChecked(false);
                }

                return true;

            default:
                return super.onOptionsItemSelected(item);
        }
    }

    private ArrayList<Log> loadLog()    {
        /** Access folder "my_logs" in external memory */
        File baseDir = new File(Environment.getExternalStorageDirectory().getAbsolutePath() +
                                File.separator +
                                "50802566/logs");
        if (!baseDir.exists())  {   baseDir.mkdirs();   }
        File[] list_file = baseDir.listFiles();

        /** For internal memory */
        //File[] list_file = this.getFilesDir().listFiles();

        for (int i = 0; i < list_file.length; i ++) {
            //android.util.Log.e("PRINTLN", list_file[i].getPath());
        }

        int l = list_file.length;

        ArrayList<Log> list = new ArrayList<Log>();

        while (l-- > 0) {
            File file = list_file[l];

            FileInputStream fin = null;
            LogReader logr = new LogReader();

            try {
                fin = new FileInputStream(file);
                list.add(list_file.length - l - 1, logr.read(fin));
                fin.close();
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            } catch (XmlPullParserException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        return list;
    }
}

问题是:

  1. 我无法跟踪每个CheckBox的布尔值。例如,如果我将logList(我的数据库)和“notifyDataSetChanged”排序到listView,但我的checkList(包含CheckBoxes的布尔值)仍然是相同的,并且会发生奇怪的事情。如何将一个列表的所有排序操作完全应用于另一个列表? (IMO,“同步排序”或类似的东西......)

  2. 正如您所看到的,我尝试通过从其行中获取del_box(我的CheckBox ID)来解决#1,然后设置其“OnCheckedChangeListener”来进行分配(一旦选中,它将更新相对布尔列表中的值“checkList”)。但奇怪的事情又发生了:

    • 当检查一行并向下滚动时,我看到另一个(自动)检查。
    • 向后滚动时,前一个选中的...将被取消选中(当然是自动)。
  3. 也许适配器正在重复使用错误的视图/值,但我不知道如何让它做正确的事情......&gt;“&lt;

    您的帮助和指南非常棒。您的示例代码对我来说将是完美的...(我现在真的很累&gt;“&lt;)

    更新

    我找到了一种方法(以某种方式)解决它,但也许它违反Android的API行为......如果你有更安全的解决方案,请告诉我^^

    正如我在第二条评论中所提到的,这是代码:

    @Override
        public void onCheckedChanged(CompoundButton cb, boolean isChecked) {
            int graphicalPos = -1;
    
            // This is top view on the screen for sure
            if (((View)cb.getParent()).getTop() < 0)    {
                graphicalPos = 0;
            }
    
            else if (((View)cb.getParent()).getTop() == 0)  {
                graphicalPos = (int) (((View)cb.getParent()).getTop() / ((View)cb.getParent()).getHeight());
            }
    
            else if (((View)cb.getParent()).getTop() > 0)   {
                graphicalPos = (int) (((View)cb.getParent()).getTop() / ((View)cb.getParent()).getHeight());
                if (listView.getChildAt(0).getTop() < 0)    {
                    graphicalPos = graphicalPos + 1;
                }
    
                else    {
                    android.util.Log.e("NOT PLUS", "First Top = " + listView.getChildAt(0).getTop());
                }
            }
    
            int dataPos = graphicalPos + listView.getFirstVisiblePosition();
    
            lw_adapter.checkList.set(dataPos, isChecked);
            android.util.Log.e("onCheckedChanged", "Checked row " + dataPos + ", graphicalPos = " + graphicalPos + ", top = " + ((View)cb.getParent()).getTop() + ", firstVisible = " + listView.getFirstVisiblePosition());
        }
    

0 个答案:

没有答案