android - Android Studio - Listview OnClick 激活多个复选框
问题描述
你好,我是 Androidstudio 的初学者。
我试图创建一个带有复选框和 TextView 的 Listview 乍一看,它看起来像它的工作,但问题是我选中了“我的笔记:0”的复选框并且选中了“我的笔记:9”的复选框,我有不知道为什么,调试也无济于事。
不仅注 9 被检查每个: 8 +1 的倍数被检查。所以有些勾选的是9、17、25、33、41、49、57、65、73、81……
列表视图 XML:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:weightSum="100">
<CheckBox android:gravity="center"
android:text=""
android:layout_width="match_parent"
android:layout_height="60dp"
android:id="@+id/checkBox_shopEntry"
android:layout_weight="90"/>
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="10">
<TextView
android:id="@+id/textView_feedbackName"
android:layout_width="match_parent"
android:layout_height="60dp"
android:layout_gravity="left"
android:fontFamily="casual"
android:gravity="center|left"
android:text="TextView1" />
</LinearLayout>
</LinearLayout>
ListView 适配器:
package com.example.fragment.Entity;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.widget.ArrayAdapter;
import android.widget.CheckBox;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.example.fragment.R;
import java.util.ArrayList;
public class ShopListAdapter extends ArrayAdapter<ShoppingEntry> {
private static final String TAG = "ShopListAdapter";
private Context mContext;
private int mResource;
private int lastPosition = -1;
/**
* Holds variables in a View
*/
private static class ViewHolder {
TextView name;
CheckBox checkBox;
}
public ShopListAdapter(Context context, int resource, ArrayList<ShoppingEntry> objects) {
super(context, resource, objects);
mContext = context;
mResource = resource;
}
@Override
public void add(@Nullable ShoppingEntry object) {
super.add(object);
}
@NonNull
@Override
public View getView(int position, View convertView, ViewGroup parent) {
//get the shop list information
String name = getItem(position).getName();
//Create the shopEntry object with the information
ShoppingEntry shopEntry = new ShoppingEntry(name);
//create the view result for showing the animation
final View result;
//ViewHolder object
ViewHolder holder;
if(convertView == null){
LayoutInflater inflater = LayoutInflater.from(mContext);
convertView = inflater.inflate(mResource, parent, false);
holder= new ViewHolder();
holder.name = (TextView) convertView.findViewById(R.id.textView_feedbackName);
holder.checkBox = convertView.findViewById(R.id.checkBox_shopEntry);
result = convertView;
convertView.setTag(holder);
}
else{
holder = (ViewHolder) convertView.getTag();
result = convertView;
}
Animation animation = AnimationUtils.loadAnimation(mContext,
(position > lastPosition) ? R.anim.load_down_anim : R.anim.load_up_anim);
result.startAnimation(animation);
lastPosition = position;
holder.name.setText(shopEntry.getName());
return convertView;
}
}
以及Adapter中使用的Object
package com.example.fragment.Entity;
public class ShoppingEntry {
private String name;
public ShoppingEntry(String note) {
this.name = note;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
解决方案
您面临的问题与ListView
回收视图的方式有关。
您可能已经意识到这一点,因为您已经考虑到getView()
了这一点:
if(convertView == null){
// Inflate a new View
}
else{
// reuse the recylced view
}
所以ListView
只有根据需要渲染尽可能多的项目来填充屏幕。在您开始滚动之前,它不会创建更多项目,并且当您开始滚动时,ListView
开始重用已超出屏幕的膨胀视图。
因此,当您向下滚动时,Note 0 的视图会离开屏幕并ListView
重新使用即将进入屏幕的 Note 9 的视图。
这将导致您看到“我的笔记:0”再次从底部显示,但您的代码已经通过使用正确的数字重新设置项目的文本来处理此问题:
holder.name.setText(shopEntry.getName());
但它仍然是用于 Note 0 的完全相同的 View 对象。即使您确实使用正确的数字“9”更新了文本,复选框的状态仍与 Note 0 相同,因为它仍然是同一个对象.
要解决这个问题,你需要做两件事:
- 将每个 Shop Entry 项目的“已检查”状态存储在某处
- Inisde
getView()
,将复选框的状态设置为相关条目的选中状态
像这样的东西:
// Store a list of checked items. Update as items are checked/unchecked
private ArrayList<ShopEntry> checkedEntries = new ArrayList();
@NonNull
@Override
public View getView(int position, View convertView, ViewGroup parent) {
.
.
.
if(convertView == null){
LayoutInflater inflater = LayoutInflater.from(mContext);
convertView = inflater.inflate(mResource, parent, false);
holder= new ViewHolder();
holder.name = (TextView) convertView.findViewById(R.id.textView_feedbackName);
holder.checkBox = convertView.findViewById(R.id.checkBox_shopEntry);
// Update the list of checked items when the user checks or unchecks an item
holder.checkBox.setOnCheckedChangeListener(new OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView,
boolean isChecked) {
if(isChecked && !checkedEntries.contains(shopEntry)) {
checkedEntries.add(shopEntry);
} else {
checkedEntries.remove(shopEntry);
}
}
});
result = convertView;
convertView.setTag(holder);
}
else{
holder = (ViewHolder) convertView.getTag();
result = convertView;
}
.
.
.
holder.name.setText(shopEntry.getName());
// reset the checbkox state too!
holder.checkBox.setChecked(checkedEntries.contains(shopEntry));
return convertView;
}
警告:我编写此代码的系统上没有安装 Android Studio,因此我没有测试此代码。对此感到抱歉。但我希望我传达了大致的想法。您可能希望以自己(更好)的方式实现整个“跟踪检查哪些项目”的事情。
推荐阅读
- javascript - 在JS中对两个长十六进制值执行按位运算的最有效方法是什么?
- python - 浏览对象成员以查找某些特定结果
- javascript - Promises.all 函数在数据准备好之前解析
- r - 如何根据 R 中的 DATE 合并两个数据集 - 使用代码
- docker - 在我的 M1 Macbook 上构建 Alpine 映像时收到错误
- javascript - 反应询问jwt是否对重定向有效
- webpack - 我可以使用 webpack 捆绑 Next.js 自定义服务器吗?
- php - 错误:调用数组上的成员函数。在foreach里面。Symfony
- javascript - 数组值的计算在 JS 中不起作用
- javascript - 如何获得在用户同意期间授予范围的用户的子用户?