取消选择并向下滚动后,列表视图中的复选框被选中。

Posted

技术标签:

【中文标题】取消选择并向下滚动后,列表视图中的复选框被选中。【英文标题】:Checkbox in listview getting selected after unselecting it and scrolling down. 【发布时间】:2015-11-30 10:10:14 【问题描述】:

我知道有人提出了多个与我的问题类似的问题,但尚未解决我的特定问题。

我有一个 BaseAdapter,它准备了一个带有复选框的列表。

这里是适配器的相关代码——

 @Override
    public View getView(final int position, View convertView, ViewGroup parent) 
        selectedFolderIds = new ArrayList<>();
        selectedFolderNames = new ArrayList<>();
        selectedFolderParentIds = new ArrayList<>();
        deselectedFolderIds = new ArrayList<>();

        final FolderStructureDataModel folderDetails = (FolderStructureDataModel) getItem(position);

        final ViewHolder holder;
        LayoutInflater inflater = (LayoutInflater) context
                .getSystemService(Context.LAYOUT_INFLATER_SERVICE);

        if(convertView == null) 
            convertView = inflater.inflate(R.layout.folder_structure_list_item_template,
                    parent, false);
            holder = new ViewHolder();
            holder.folderListLayout = (RelativeLayout) convertView.findViewById(R.id.folder_list_layout);
            holder.childFoldersIndicator = (ImageView)
                    convertView.findViewById(R.id.child_folders_indicator);
            holder.selectionCheckBox = (CheckBox) convertView.findViewById(R.id.checkbox);

            convertView.setTag(holder);
         else 
            holder = (ViewHolder) convertView.getTag();
            holder.selectionCheckBox.setOnCheckedChangeListener(null);
            holder.selectionCheckBox.setOnClickListener(null);
        

        /**
         * Attach the listeners to the checkboxes.
         */
        holder.selectionCheckBox.setOnClickListener(new View.OnClickListener() 
            @Override
            public void onClick(View view) 
                CheckBox cb = (CheckBox) view;
                if (cb.isChecked()) 
                    selectedFolderIds.add(HelperFunctions.EncodeString(folderDetails.ID));
                    selectedFolderNames.add(HelperFunctions.EncodeString(folderDetails.DisplayName));
                    selectedFolderParentIds.add(HelperFunctions.EncodeString(folderDetails.ParentFolderID));

                    SelectedFolderListener selectedFolderListener =
                            (SelectedFolderListener) context;
                    selectedFolderListener.getSelectedFoldersArrayList(selectedFolderIds,
                            selectedFolderNames, selectedFolderParentIds);

                    Log.i("Test : " + folderDetails.DisplayName + " at position " +
                            String.valueOf(position), "Set to " +
                            String.valueOf(checkboxStatus.get(position))
                            + " From onClickListener");
                 else 
                    selectedFolderIds.remove(HelperFunctions.EncodeString(folderDetails.ID));
                    selectedFolderNames.remove(HelperFunctions
                            .EncodeString(folderDetails.DisplayName));
                    selectedFolderParentIds.remove(HelperFunctions
                            .EncodeString(folderDetails.ParentFolderID));
                    deselectedFolderIds.add(HelperFunctions.EncodeString(folderDetails.ID));

                    UnselectedFolderListener unselectedFolderListener =
                            (UnselectedFolderListener) context;
                    unselectedFolderListener.getDeselectedFolderArrayList(deselectedFolderIds);

                    Log.i("Test : " + folderDetails.DisplayName + " at position " +
                            String.valueOf(position), "Set to " +
                            String.valueOf(checkboxStatus.get(position))
                            + " From onClickListener");
                
            
        );

        holder.selectionCheckBox.setOnCheckedChangeListener
                (new CompoundButton.OnCheckedChangeListener() 

                    @Override
                    public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) 

                        if (((buttonView).isChecked()) && isChecked) 
                            checkboxStatus.set(position, true);
                            Log.i("Test : " + folderDetails.DisplayName + " at position " +
                                    String.valueOf(position), "Set to " +
                                    String.valueOf(checkboxStatus.get(position))
                                    + " From onCheckChangedListener");
                         else 
                            checkboxStatus.set(position, false);
                            Log.i("Test : " + folderDetails.DisplayName + " at position " +
                                    String.valueOf(position), "Set to " +
                                    String.valueOf(checkboxStatus.get(position))
                                    + " From onCheckChangedListener");
                        
                    
                );

        //Populate the data
        holder.selectionCheckBox.setText(String.valueOf(folderDetails.DisplayName));

        if(Integer.valueOf(folderDetails.ChildFolderCount) == 0) 
            holder.childFoldersIndicator.setVisibility(View.GONE);
            holder.folderListLayout.setFocusable(true);
            holder.folderListLayout.setClickable(true);
         else 
            holder.childFoldersIndicator.setVisibility(View.VISIBLE);
            holder.folderListLayout.setFocusable(false);
            holder.folderListLayout.setClickable(false);
        

        /**
         * Set the checkbox as per the service reply (status in the server)
         */
        if(Boolean.valueOf(folderDetails.IsAlreadySelected)) 
            holder.selectionCheckBox.setChecked(true);
            Log.i("Test : " + folderDetails.DisplayName + " at position " +
                    String.valueOf(position), "Set to " +
                    String.valueOf(holder.selectionCheckBox.isChecked()) + " From folderDetails");
         else 
            holder.selectionCheckBox.setChecked(false);
            Log.i("Test : " + folderDetails.DisplayName + " at position " +
                    String.valueOf(position), "Set to " +
                    String.valueOf(holder.selectionCheckBox.isChecked()) + " From folderDetails");
        

        /**
         * Set the checkbox as per the values maintained in the checkboxStatus ArrayList
         */
        if(checkboxStatus.get(position)) 
            holder.selectionCheckBox.setChecked(true);
            Log.i("Test : " + folderDetails.DisplayName + " at position " +
                    String.valueOf(position), "Set to " +
                    String.valueOf(holder.selectionCheckBox.isChecked()) + " From checkBoxStatus");
         else 
            holder.selectionCheckBox.setChecked(false);
            Log.i("Test : " + folderDetails.DisplayName + " at position " +
                    String.valueOf(position), "Set to " +
                    String.valueOf(holder.selectionCheckBox.isChecked()) + " From checkBoxStatus");
        

        return convertView;
    

我有一个ArrayListcheckboxStatus,它维护每个位置复选框的状态。

我面临的问题是,如果一个复选框已被选中(根据“folderDetails.IsAlreadySelected”的值),我取消选中它并向下滚动然后向上滚动,该复选框将再次被选中。特殊的部分是在相反的情况下不会发生这种情况 - 如果未选中复选框,我选中它并向下滚动然后再次向上滚动;状态保持为选中状态。

适配器可能有什么问题?

【问题讨论】:

【参考方案1】:

要解决您的问题,请执行以下操作:

if(convertView == null) 
        convertView = inflater.inflate(R.layout.folder_structure_list_item_template,
                parent, false);
        holder = new ViewHolder();
        holder.folderListLayout = (RelativeLayout) convertView.findViewById(R.id.folder_list_layout);
        holder.childFoldersIndicator = (ImageView)
                convertView.findViewById(R.id.child_folders_indicator);
        holder.selectionCheckBox = (CheckBox) convertView.findViewById(R.id.checkbox);
  // Add this line, set tag on your checkbox.
 holder.selectionCheckBox .setTag(holder);
        convertView.setTag(holder);
    

现在在 clicklistner 上,

 holder.selectionCheckBox.setOnClickListener(new View.OnClickListener() 
        @Override
        public void onClick(View view) 
         // add this line,declare holder_new as an instance of ViewHolder
        holder_new= (ViewHolder) view.getTag();
            // rest is your code what you have already written
    );

现在在 onclick 之后,无论您使用 holder 访问 selectionCheckBox 的任何位置,都将其更改为 holder_new。

holder.selectionCheckBox.setChecked(true); 将其更改为 holder_new.selectionCheckBox.setChecked(true);

【讨论】:

holder_new== (ViewHolder) view.getTag(); 我猜你的意思是holder_new = (ViewHolder) view.getTag();,对吧?另外,我在哪里声明holder_view yup.. 输入错误:P 在声明“持有人”的同一位置声明它。由您决定,您也可以在类级别声明它。 我必须使它成为全局的,否则我会得到variable accessed from inner class needs to be declared final 错误。我通过上述更改尝试了您的实现,但由于 holder_new.selectionCheckBox.setChecked(true); 处的 NullPointerException,活动正在崩溃 //添加这一行,将 holder_new 声明为 ViewHolder 的一个实例 holder_new= (ViewHolder) view.getTag();你没有初始化 holder_new 吗? 我做到了。我创建了一个全局变量holder_new,在适配器构造函数中使用viewHolder = new ViewHolder(); 启动它,然后按照您上面所说的进行操作。我仍然得到一个 NPE。

以上是关于取消选择并向下滚动后,列表视图中的复选框被选中。的主要内容,如果未能解决你的问题,请参考以下文章

滚动列表视图 BaseAdapter 上的复选框选中/未选中状态更改

滚动后未选中 ListView 适配器中的 Android 复选框

当我在 Android 上滚动列表视图时复选框未选中

当我滚动列表视图单选按钮被自动选择或取消选择无法保持单选按钮的状态

向下滚动时如何使 UIButton 在表格视图中保持选中状态

从上到下滚动时如何自动停止对项目的列表视图取消选择?