首页 > 解决方案 > 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;
    }

}

标签: androidandroid-studiolistviewcheckbox

解决方案


您面临的问题与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 相同,因为它仍然是同一个对象.

要解决这个问题,你需要做两件事:

  1. 将每个 Shop Entry 项目的“已检查”状态存储在某处
  2. 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,因此我没有测试此代码。对此感到抱歉。但我希望我传达了大致的想法。您可能希望以自己(更好)的方式实现整个“跟踪检查哪些项目”的事情。


推荐阅读