使用CursorAdapter维护listview中的复选框状态 [英] Maintaining checkbox states in listview with CursorAdapter
问题描述
对于我的Android项目,我有一个列表视图,每个项目都有一个复选框。通过使用CursorAdapter类从SQLite数据库加载数据。然而,每当我滚动,复选框位置将被移动,并被带到列表视图的下一部分。如何解决这个问题?
)。
原因: ListView重新使用视图。
解决方案: / strong>
class VocabCursorAdapter extends CursorAdapter {
List< Integer> selectedItemsPositions; //存储所有选定的项目position
public VocabCursorAdapter(Context context,Cursor c,int flags){
super(context,c,0);
selectedItemsPositions = new ArrayList<>();
}
@Override
public View newView(Context context,Cursor cursor,ViewGroup viewGroup){
View view = LayoutInflater.from(context).inflate .layout.item_vocab,viewGroup,false);
CheckBox box =(CheckBox)view.findViewById(R.id.editCheckbox);
box.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener(){
@Override
public void onCheckedChanged(CompoundButton compoundButton,boolean b){
int position =(int)compoundButton.getTag );
if(b){
//检查它是否已被选中
if(!selectedItemsPositions.contains(position))
selectedItemsPositions.add(position);
} else {
//如果未选中则删除位置选中项
selectedItemsPositions.remove((Object)position);
}
}
}
return view;
}
@Override
public void bindView(View view,Context context,Cursor cursor){
//你的其他东西
CheckBox box =(CheckBox)view.findViewById(R.id.editCheckbox);
box.setTag(cursor.getPosition());
if(selectedItemsPositions.contains(cursor.getPosition()))
box.setChecked(true);
else
box.setChecked(false);
}
}
happyCoding;
For my Android project, I have a listview which has a checkbox for every item. The data is loaded from an SQLite database by using a CursorAdapter class. However, whenever I scroll, the checkbox positions will get moved and get carried down to the next part of the listview. How can I fix this problem? GIF of my CheckBox Problem Here's my Cursor Adapter Class:
public class VocabCursorAdapter extends CursorAdapter {
private static final int DIFFICULT = 0;
private static final int FAMILIAR = 1;
private static final int EASY = 2;
private static final int PERFECT = 3;
public VocabCursorAdapter(Context context, Cursor c, int flags) {
super(context, c, 0);
}
@Override
public View newView(Context context, Cursor cursor, ViewGroup parent) {
return LayoutInflater.from(context).inflate(R.layout.item_vocab, parent, false);
}
@Override
public void bindView(View view, Context context, Cursor cursor) {
// Find fields to populate in inflated template
TextView tvVocabName = (TextView) view.findViewById(R.id.vocabName);
TextView tvVocabDefinition = (TextView) view.findViewById(R.id.vocabDefinition);
ImageView tvVocabLevel = (ImageView) view.findViewById(R.id.vocabLevel);
// Extract properties from cursor
String vocab = cursor.getString(cursor.getColumnIndexOrThrow(VocabDbContract.COLUMN_NAME_VOCAB));
String definition = cursor.getString(cursor.getColumnIndexOrThrow(VocabDbContract.COLUMN_NAME_DEFINITION));
int level = cursor.getInt(cursor.getColumnIndexOrThrow(VocabDbContract.COLUMN_NAME_LEVEL));
// Populate fields with extracted properties
tvVocabName.setText(vocab);
tvVocabDefinition.setText(definition);
if (level == DIFFICULT) {
tvVocabLevel.setImageResource(R.drawable.level_bars_difficult);
tvVocabLevel.setTag(DIFFICULT);
}
else if (level == FAMILIAR) {
tvVocabLevel.setImageResource(R.drawable.level_bars_familiar);
tvVocabLevel.setTag(FAMILIAR);
}
else if (level == EASY) {
tvVocabLevel.setImageResource(R.drawable.level_bars_easy);
tvVocabLevel.setTag(EASY);
}
else if (level == PERFECT) {
tvVocabLevel.setImageResource(R.drawable.level_bars_perfect);
tvVocabLevel.setTag(PERFECT);
}
}
And here's my list item xml, item_vocab.xml:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:longClickable="true">
<ImageView
android:layout_width="36sp"
android:layout_height="36sp"
android:id="@+id/vocabLevel"
android:layout_gravity="right"
android:src="@drawable/level_bars"
android:scaleType="fitXY"
android:contentDescription="@string/vocab_level"
android:layout_centerVertical="true"
android:layout_toLeftOf="@+id/editCheckbox"
android:layout_toStartOf="@+id/editCheckbox"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceLarge"
android:text="Large Text"
android:id="@+id/vocabName"
android:layout_alignParentTop="true"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_toLeftOf="@+id/vocabLevel"
android:layout_toStartOf="@+id/vocabLevel"/>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceSmall"
android:text="Small Text"
android:id="@+id/vocabDefinition"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_toLeftOf="@+id/vocabLevel"
android:layout_toStartOf="@+id/vocabLevel"
android:layout_below="@id/vocabName"/>
<CheckBox
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/editCheckbox"
android:layout_centerVertical="true"
android:layout_alignParentRight="true"
android:layout_alignParentEnd="true"/>
</RelativeLayout>
And here's my xml which contains a listview
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".controller.MyVocab"
android:paddingLeft="5dp">
<ListView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:id="@+id/mVocabList"
android:layout_alignParentTop="true"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"/>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/empty_text_view"
android:id="@android:id/empty"
android:layout_alignParentTop="true"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"/>
</RelativeLayout>
I have looked at a lot of different solutions on StackOverflow, but I wasn't able to successfully do it in my own app. For an example, this post has a similar problem, but its solution used getView and I had trouble understanding how to implement it with newView and bindView instead.
And some other solutions might be examples where a cursoradapter is not involved. Any help is much appreciated, thanks a lot! Edit #1: After incorporating Phan's changes, the checkbox states get resets to false rather than keeping its states when I scroll the listview (See ).
Reason : ListView re-uses the views.
Solution :
class VocabCursorAdapter extends CursorAdapter {
List<Integer> selectedItemsPositions;//to store all selected items position
public VocabCursorAdapter(Context context, Cursor c,int flags) {
super(context, c,0);
selectedItemsPositions = new ArrayList<>();
}
@Override
public View newView(Context context, Cursor cursor, ViewGroup viewGroup) {
View view = LayoutInflater.from(context).inflate(R.layout.item_vocab, viewGroup, false);
CheckBox box = (CheckBox) view.findViewById(R.id.editCheckbox);
box.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton compoundButton, boolean b) {
int position = (int) compoundButton.getTag();
if (b) {
//check whether its already selected or not
if (!selectedItemsPositions.contains(position))
selectedItemsPositions.add(position);
} else {
//remove position if unchecked checked item
selectedItemsPositions.remove((Object) position);
}
}
});
return view;
}
@Override
public void bindView(View view, Context context, Cursor cursor) {
//your other stuff
CheckBox box = (CheckBox) view.findViewById(R.id.editCheckbox);
box.setTag(cursor.getPosition());
if (selectedItemsPositions.contains(cursor.getPosition()))
box.setChecked(true);
else
box.setChecked(false);
}
}
happyCoding;
这篇关于使用CursorAdapter维护listview中的复选框状态的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!