滚动列表视图时,复选框会自动取消选中

时间:2016-03-11 12:02:15

标签: android listview

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

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;
    }

}

6 个答案:

答案 0 :(得分:2)

问题是因为正在重新制作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

答案 1 :(得分:1)

  1. 声明一个布尔数组,用于保存每个列表项的选中状态。

  2. 在构造函数中初始化(使用for循环)此数组(全部分配为false)。

  3. 记录setOnCheckedChangeListener()内部的更改。

  4. setChecked()之后致电setOnCheckedChangeListener()

答案 2 :(得分:0)

尝试使用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

答案 3 :(得分:0)

如果您使用的是apply plugin: 'com.android.library' apply plugin: 'com.jfrog.artifactory' apply plugin: 'maven-publish' android { compileSdkVersion 23 buildToolsVersion "23.0.2" defaultConfig { minSdkVersion 9 targetSdkVersion 23 versionCode 1 versionName "0.0.1" } publishNonDefault true buildTypes { debug { minifyEnabled false debuggable true } release { minifyEnabled false debuggable false } snapshot { minifyEnabled false debuggable false } } } task androidJavadocs(type: Javadoc) { source = android.sourceSets.main.java.srcDirs classpath += project.files(android.getBootClasspath().join(File.pathSeparator)) } task androidJavadocsJar(type: Jar, dependsOn: androidJavadocs) { classifier = 'javadoc' from androidJavadocs.destinationDir } task androidSourcesJar(type: Jar) { classifier = 'sources' from android.sourceSets.main.java.srcDirs } artifacts { archives androidSourcesJar archives androidJavadocsJar } publishing { publications { android.buildTypes.all { variant -> "${variant.name}"(MavenPublication) { def manifestParser = new com.android.builder.core.DefaultManifestParser() groupId manifestParser.getPackage(android.sourceSets.main.manifest.srcFile) if("${variant.name}".equalsIgnoreCase("release")){ version = manifestParser.getVersionName(android.sourceSets.main.manifest.srcFile) }else if ("${variant.name}".equalsIgnoreCase("debug")){ version = manifestParser.getVersionName(android.sourceSets.main.manifest.srcFile).concat("-${variant.name}".toUpperCase().concat("-SNAPSHOT")) }else{ version = manifestParser.getVersionName(android.sourceSets.main.manifest.srcFile).concat("-${variant.name}".toUpperCase()) } artifactId project.getName() artifact("$buildDir/outputs/aar/${project.getName()}-${variant.name}.aar") artifact androidJavadocsJar pom.withXml { def dependencies = asNode().appendNode('dependencies') configurations.getByName("_releaseCompile").getResolvedConfiguration().getFirstLevelModuleDependencies().each { def dependency = dependencies.appendNode('dependency') dependency.appendNode('groupId', it.moduleGroup) dependency.appendNode('artifactId', it.moduleName) dependency.appendNode('version', it.moduleVersion) } } } } } } android.buildTypes.all { variant -> model { tasks."generatePomFileFor${variant.name.capitalize()}Publication" { destination = file("$buildDir/publications/${variant.name}/generated-pom.xml") } } def publicationName = "${variant.name}" def taskName = "${variant.name}Publication" task "$taskName"() << { artifactoryPublish { doFirst { tasks."generatePomFileFor${variant.name.capitalize()}Publication".execute() publications(publicationName) clientConfig.publisher.repoKey = "${variant.name}".equalsIgnoreCase("release") ? "libs-release-local" : "libs-snapshot-local" } } } tasks."assemble${variant.name.capitalize()}".dependsOn(tasks."$taskName") } artifactory { contextUrl = 'http://172.16.32.220:8081/artifactory' publish { repository { username = "admin" password = "password" } defaults { publishPom = true publishArtifacts = true properties = ['qa.level': 'basic', 'dev.team': 'core'] } } } dependencies { compile fileTree(dir: 'libs', include: ['*.jar']) testCompile 'junit:junit:4.12' compile 'com.android.support:appcompat-v7:23.1.1' } ,那么您的适配器应该实现listView,以便在复选框状态中保存更改。在您必须实现OnCheckedChangeListener的方法(在getView()中编写)中,您必须从SharedPreferences获取该复选框的状态并更新它。

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

答案 4 :(得分:0)

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

当在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);
        }
    });

希望这会让您对自己的想法有所了解

答案 5 :(得分:0)

您应该使用 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)

    }
}