【问题标题】:Checkbox unchecked automatically while scrolling listview滚动列表视图时自动取消选中复选框
【发布时间】:2016-03-11 12:02:15
【问题描述】:

我有一个带有复选框和文本框的列表视图。当我选中复选框并上下滚动它时,它会自动取消选中。 如何在列表视图中解决这个问题?请给我解决方案。
下面我放了我的屏幕截图和代码。

screen shot

activity_main.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >

    <ListView
        android:id="@+id/lvMain"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1" />

        <Button
            android:id="@+id/btnSelectAll"
            android:layout_height="wrap_content"
            android:layout_width="match_parent"
            android:text="Select All" >
        </Button>
    </LinearLayout>

list_item.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="horizontal" >

    <CheckBox
        android:id="@+id/cbItem"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:buttonTint="#000000">
    </CheckBox>

    <TextView
        android:id="@+id/tvItem"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textColor="#000000">
    </TextView>

</LinearLayout>

MainActivity.java

package com.example.checkallcheckbox;

import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.ListView;

public class MainActivity extends Activity {
    ListView lvMain;
    String[] name = { "Jenis", "Pratik", "Jaydeep", "Hiren", "Himansu",
            "yagnik", "Atul", "Prakas", "Nihal", "Darshan", "Chetan", "Sagar",
            "Nikhil", "Sanket", "Rahul", "Jigar" };

    Button btnSelectAll;
    boolean isSelectAll = true;
    ListAdapter adapter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        lvMain = (ListView) findViewById(R.id.lvMain);
        btnSelectAll = (Button) findViewById(R.id.btnSelectAll);

        btnSelectAll.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View arg0) {
                // TODO Auto-generated method stub
                if(isSelectAll)
                {
                adapter = new ListAdapter(getApplicationContext(), name, true);
                lvMain.setAdapter(adapter);
                adapter.notifyDataSetChanged();
                btnSelectAll.setText("ClearAll");
                isSelectAll=false;
                }
                else
                {
                    adapter = new ListAdapter(getApplicationContext(), name, false);
                    lvMain.setAdapter(adapter);
                    adapter.notifyDataSetChanged();
                    btnSelectAll.setText("CheckAll");
                    isSelectAll=true;

                }

            }
        });

        adapter = new ListAdapter(getApplicationContext(), name,false);
        lvMain.setAdapter(adapter);
        adapter.notifyDataSetChanged();

    }
}

ListAdapter.java

package com.example.checkallcheckbox;

import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.CheckBox;
import android.widget.TextView;

public class ListAdapter extends BaseAdapter {

    Context mContext;
    String[] name;
    private static LayoutInflater inflater = null;
    Boolean state=false;

    public ListAdapter(Context c, String[] name, boolean isSelectAll) {
        // TODO Auto-generated constructor stub
        mContext = c;
        this.name = name;
        inflater = (LayoutInflater) mContext
                .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        state=isSelectAll;
    }

    @Override
    public int getCount() {

        return name.length;
    }

    @Override
    public Object getItem(int position) {
        // TODO Auto-generated method stub
        return position;
    }

    @Override
    public long getItemId(int position) {
        // TODO Auto-generated method stub
        return position;
    }

    public class ViewHolder {
        TextView tvName;
        CheckBox cbName;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup arg2) {
        // TODO Auto-generated method stub
        ViewHolder viewHolder;

        if (convertView == null) {

            convertView = inflater.inflate(R.layout.list_item, null);
            viewHolder = new ViewHolder();
            viewHolder.tvName = (TextView) convertView
                    .findViewById(R.id.tvItem);
            viewHolder.cbName = (CheckBox) convertView
                    .findViewById(R.id.cbItem);
            convertView.setTag(viewHolder);
        } else {
            viewHolder = (ViewHolder) convertView.getTag();
        }

        viewHolder.tvName.setText(name[position]);

        if(state){
            viewHolder.cbName.setChecked(true);
        }else{
            viewHolder.cbName.setChecked(false);
        }

        return convertView;
    }

}

【问题讨论】:

标签: android listview


【解决方案1】:

问题是因为您的 ListView 视图正在重新制作。当您将它们滚动到屏幕外时,android 不会保留它们(列表可能真的很长,所以这意味着有很多您看不到的视图)。

因此,每次您在屏幕上滚动一个项目时,Android 都会再次调用 getView,然后您返回一个未选中复选框的视图。

您需要做的是在每个列表项上设置一个单击/检查的侦听器,以便能够记住它们何时被检查。然后当android要求你查看时,你可以检查是否应该检查。

您可以看到getItem 方法已经可以帮助您解决这个问题。您可以尝试覆盖ArrayAdapter,因为这将让您存储一些可以保持“点击”状态的简单对象。见:http://developer.android.com/reference/android/widget/ArrayAdapter.html

这就是为什么 Aditya 会问你模特班在哪里。目前你只有一个学生列表,你想要的是一个学生列表以及他们是否被选中。也许是这样的课程:

class Student
{
    private String mName;
    public Boolean selected;

    public Student(String name)
    {
        mName = name;
    }

    public String getName()
    {
        return mName;
    }
}

然后你可以有一个数组来代替。当一个项目被点击时,你在相关的学生项目上设置selected。

您的getView 可能如下所示:

@Override
public View getView(int position, View convertView, ViewGroup arg2) {
    // TODO Auto-generated method stub
    ViewHolder viewHolder;

    if (convertView == null) {

        convertView = inflater.inflate(R.layout.list_item, null);
        viewHolder = new ViewHolder();
        viewHolder.tvName = (TextView) convertView
                .findViewById(R.id.tvItem);
        viewHolder.cbName = (CheckBox) convertView
                .findViewById(R.id.cbItem);
        convertView.setTag(viewHolder);
    } else {
        viewHolder = (ViewHolder) convertView.getTag();
    }

    Student thisStudent = students[position];
    viewHolder.tvName.setText(thisStudent.getName());

    if(state || thisStudent.selected){
        viewHolder.cbName.setChecked(true);
    }else{
        viewHolder.cbName.setChecked(false);
    }

    return convertView;
}

关于这方面有很多指南,这里有一个这样的指南,解释了视图回收在列表中的工作原理(您的问题)以及如何使用 ArrayAdapter https://github.com/codepath/android_guides/wiki/Using-an-ArrayAdapter-with-ListView

【讨论】:

    【解决方案2】:

    如果您使用listView,您的适配器应实现OnCheckedChangeListener,以便保存复选框状态的更改。在您必须实现onCheckedChanged()(将其写入getView() 中)的方法中,您必须从SharedPreferences 中获取该复选框的状态并对其进行更新。

    如果你寻找这种方法,你会发现一些例子,这里是one

    【讨论】:

      【解决方案3】:
      1. 声明一个布尔数组,用于保存每个列表项的选中状态。

      2. 在构造函数中初始化(使用for循环)这个数组(全部赋值为假)。

      3. 记录setOnCheckedChangeListener()内的变化。

      4. 在setOnCheckedChangeListener()之后调用setChecked()。

      【讨论】:

        【解决方案4】:

        尝试与 RecycleView 一起使用,

        public class CardViewActivity extends ActionBarActivity {
        
         private Toolbar toolbar;
        
         private RecyclerView mRecyclerView;
         private RecyclerView.Adapter mAdapter;
         private RecyclerView.LayoutManager mLayoutManager;
        
         private List<Student> studentList;
        
         private Button btnSelection;
        
         @Override
         protected void onCreate(Bundle savedInstanceState) {
          super.onCreate(savedInstanceState);
          setContentView(R.layout.activity_main);
          toolbar = (Toolbar) findViewById(R.id.toolbar);
          btnSelection = (Button) findViewById(R.id.btnShow);
        
          studentList = new ArrayList<Student>();
        
          for (int i = 1; i <= 15; i++) {
           Student st = new Student("Student " + i, "androidstudent" + i
             + "@gmail.com", false);
        
           studentList.add(st);
          }
        
          if (toolbar != null) {
           setSupportActionBar(toolbar);
           getSupportActionBar().setTitle("Android Students");
        
          }
        
          mRecyclerView = (RecyclerView) findViewById(R.id.my_recycler_view);
        
          // use this setting to improve performance if you know that changes
          // in content do not change the layout size of the RecyclerView
          mRecyclerView.setHasFixedSize(true);
        
          // use a linear layout manager
          mRecyclerView.setLayoutManager(new LinearLayoutManager(this));
        
          // create an Object for Adapter
          mAdapter = new CardViewDataAdapter(studentList);
        
          // set the adapter object to the Recyclerview
          mRecyclerView.setAdapter(mAdapter);
        
          btnSelection.setOnClickListener(new OnClickListener() {
        
           @Override
           public void onClick(View v) {
            String data = "";
            List<Student> stList = ((CardViewDataAdapter) mAdapter)
              .getStudentist();
        
            for (int i = 0; i < stList.size(); i++) {
             Student singleStudent = stList.get(i);
             if (singleStudent.isSelected() == true) {
        
              data = data + "\n" + singleStudent.getName().toString();
              /*
               * Toast.makeText( CardViewActivity.this, " " +
               * singleStudent.getName() + " " +
               * singleStudent.getEmailId() + " " +
               * singleStudent.isSelected(),
               * Toast.LENGTH_SHORT).show();
               */
             }
        
            }
        
            Toast.makeText(CardViewActivity.this,
              "Selected Students: \n" + data, Toast.LENGTH_LONG)
              .show();
           }
          });
        
         }
        

        更多信息请见this

        对于 ListView,请参阅this

        【讨论】:

          【解决方案5】:

          我能够解决我的问题,这也可能对您有所帮助。

          当滚动浏览绑定在 RecyclerView 上的复选框的 ArrayList 时,我遇到了同样的自动选择和取消选择问题。

          问题在于,在我的 RecyclerView 适配器中,我在 ArrayList 中的每个复选框项目上设置了一个 OnCheckedChange 侦听器,同时将数据绑定到视图,这使得复选框在滚动时自动选择和取消选择。

          在下面查看我的初始代码;

          holder.subCategoriesCheckBox.setOnCheckedChangeListener((compoundButton, b) -> {
                  if (holder.subCategoriesCheckBox.isChecked()){
                      holder.subCategoriesCheckBox.setChecked(false);
                      subCategory.setSelected(false);
                  }
                  else {
                      holder.subCategoriesCheckBox.setChecked(true);
                      subCategory.setSelected(true);
                  }
              });
          

          解决方案是在复选框上设置 OnClickListener 而不是 OncheckedChange 侦听器,如下所示;

          holder.subCategoriesCheckBox.setOnClickListener(view -> {
                  if (holder.subCategoriesCheckBox.isSelected()){
                      holder.subCategoriesCheckBox.setSelected(false);
                      subCategory.setSelected(false);
                  }
                  else {
                      holder.subCategoriesCheckBox.setSelected(true);
                      subCategory.setSelected(true);
                  }
              });
          

          希望这能让您了解如何去做自己的事情

          【讨论】:

            【解决方案6】:

            您应该使用 recyclerView 并控制列表中的检查状态,您可以添加一个 isDefault 布尔值,它会在不同行发生更改时得到更新。 我有这个here的教程@

            holder.checkBox.setOnCheckedChangeListener { _, isChecked ->
                        if (item.isChecked != isChecked) {
                            setCheckboxTextColor(isChecked, holder)
                            item.isChecked = isChecked
            
                        when (item.rowType) {
                            RowType.TopHeader -> {
                                val indexList = mutableListOf<Int>()
                                productList.filter { it.rowType != RowType.TopHeader }.forEach {
                                    it.isChecked = isChecked
                                    indexList.add(productList.indexOf(it))
                                }
                                indexList.forEach {
                                    notifyItemChanged(it)
                                }
                            }
                            RowType.CatHeader -> {
                                val indexList = mutableListOf<Int>()
                                productList.filter { it.rowType == RowType.ProductRow && it.category == item.category }
                                        .forEach {
                                            it.isChecked = isChecked
                                            indexList.add(productList.indexOf(it))
                                        }
                                indexList.forEach {
                                    notifyItemChanged(it)
                                }
                                isAllItemsSameStatus() //for header
            
                            }
                            RowType.ProductRow -> {
                                isAllItemsSameStatus(item.category) //set prep area accordingly
                                isAllItemsSameStatus() //set top header
                            }
                        }
                    }
                }
            }
            
            private fun setCheckboxTextColor(isChecked: Boolean, holder: TableViewHolder) {
                if (isChecked) {
                    holder.checkBox.setTextColor(context.getColor(R.color.black))
                } else {
                    holder.checkBox.setTextColor(context.getColor(R.color.grey))
                }
            }
            
            private fun isAllItemsSameStatus(cat: String? = null) {
               val row : RowModel
               var isChecked: Boolean = true
               var position: Int = 0
            
                if(cat != null){
                val catRow = productList.find { it.rowType == RowType.CatHeader && it.category == cat }
                    catRow?.let {
                    val subList = productList.filter { it.category == it.category && it.rowType == RowType.ProductRow }
                    isChecked = subList.filter { it.isChecked }.size == subList.size
                    position = productList.indexOf(catRow)
                }
                    if(catRow == null)
                        return
                    else
                        row = catRow
                }
                else{
                    row = productList[0]
                    isChecked = productList.filter { it.rowType != RowType.TopHeader && it.isChecked }.size == productList.size - 1
                    position = 0
                }
            
                updateHeader(row, isChecked, position)
            
            }
            
            
            private fun updateHeader(item: RowModel, isChecked: Boolean, position: Int) {
                if (item.isChecked != isChecked) // no need to update if no change
                {
                    item.isChecked = isChecked
                    notifyItemChanged(position)
            
                }
            }
            

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 2011-08-31
              • 1970-01-01
              • 1970-01-01
              • 2016-01-19
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2015-11-30
              相关资源
              最近更新 更多