RecyclerView嵌入CheckBox带来的显示问题的解决办法

android 的recyclerview(或者是listview)内部item的布局包含checkbox控件时,会遇到常见的问题:选择的checkbox后滑动listview内容时会checkbox选择的值会刷新成原来状态值(即没选中),选择listview所有checkbox值之后,只能获取当前可见的checkbox的值,向后滑动选择的值无法获取。就像下图所示,总共是有50条数据,开始的时候50条数据都没有选中,后面选中前5条数据,然后滑动列表,发现checkbox的选中状态会产生错位的现象。


我们先来看看开始的时候代码是如何写的:

MainActivity:

package com.example.yk.checkboxsingle;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.widget.LinearLayout;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class MainActivity extends AppCompatActivity {
    private RecyclerView recyclerView;
    private List<String> stringList;
    public static Map<Integer,Boolean> map;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        recyclerView= (RecyclerView) findViewById(R.id.recycler);
        stringList=new ArrayList<>();
        map=new HashMap<>();
        for (int i = 0; i < 50; i++) {
            stringList.add("第"+i+"条数据");
        }
        recyclerView.setLayoutManager(new LinearLayoutManager(this));
        recyclerView.addItemDecoration(new DividerItemDecoration(this, LinearLayout.HORIZONTAL,1,R.color.line));
        MyAdapter adapter=new MyAdapter(stringList,this);
        recyclerView.setAdapter(adapter);
    }
}
MyAdapter:

package com.example.yk.checkboxsingle;

import android.content.Context;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.CheckBox;

import java.util.List;

/**
 * Created by yk on 2016/11/11.
 */
public  class MyAdapter extends RecyclerView.Adapter<MyAdapter.ViewHolder>{
    private List<String> data;
    private Context context;
    public MyAdapter(List<String> stringList,Context context) {
        this.data=stringList;
        this.context=context;
    }

    @Override
    public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View view= LayoutInflater.from(context).inflate(R.layout.item_layout,parent,false);
        return new ViewHolder(view);
    }

    @Override
    public void onBindViewHolder(final ViewHolder holder, final int position) {
        holder.checkBox.setTag(position);
        holder.checkBox.setText(data.get(position));
    }

    @Override
    public int getItemCount() {
        return data.size();
    }

    public class ViewHolder extends RecyclerView.ViewHolder {
        private CheckBox checkBox;
        public ViewHolder(View itemView) {
            super(itemView);
            checkBox= (CheckBox) itemView.findViewById(R.id.cb_my);
        }
    }
}

解决以上问题可以采取以下思路:

重写Adapter的getView方法时,为每个checkbox添加事件响应并记录选择状态,通过获取获取状态记录值获取所有选择的checkbox值。

解决办法主要是在onBindViewHolder方法重处理:

@Override
    public void onBindViewHolder(final ViewHolder holder, final int position) {
        holder.checkBox.setText(data.get(position));
        final Integer tag=new Integer(position);//初始化一个Integer实例,其值为position
        holder.checkBox.setTag(tag);
        if (MainActivity.map.containsKey(tag)){
            holder.checkBox.setChecked(MainActivity.map.get(tag));
        }else {
            holder.checkBox.setChecked(false);//true or false 都可以,看实际需求
        }
        holder.checkBox.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (holder.checkBox.isChecked()){
                    MainActivity.map.put(tag,true);
                }else {
                    MainActivity.map.put(tag,false);
                }
            }
        });
    }
效果如图:刚开始50条数据都没选中,后来选中前3条,滑动列表,并没有产生错位。


源码下载:点击打开链接//注明:链接里的源码有个地方写错了,应为:holder.checkBox.setChecked(MainActivity.map.get(tag));以博客里的为准。

在上面基础上拓展一个需求,也是我现在公司产品经理提出来的,解决方法和上面的类似,需求大致如图:


正常情况下每个item上显示的都是必要信息,有一些不重要的信息,但又不能缺少,这些信息需要通过点击item,然后让这些信息展示出来。如果照正常写法,发现会造成和checkbox类似的效果,会产生“错位”,明明点击了最前面的item,让点击了的item隐藏的信息展示出来了,当滑动到下方时,没有被点击的item隐藏的信息也会展示出来。是不是和我们的checkbox产生的错位类似呢,按照这种思路,最终解决了这个问题,见下方效果图:


主要代码:

@Override
    public void onBindViewHolder(final ViewHolder holder, final int position) {
        holder.checkBox.setText(data.get(position));
        final Integer tag=new Integer(position);//初始化一个Integer实例,其值为position
        holder.checkBox.setTag(tag);
        holder.container.setTag(tag);
        if (MainActivity.map.containsKey(tag)){
            holder.checkBox.setChecked(MainActivity.map.get(tag));
        }else {
            holder.checkBox.setChecked(false);
        }

        if(MainActivity.isShown.containsKey(tag)){
            holder.lin.setVisibility(MainActivity.isShown.get(tag)==View.VISIBLE ? View.VISIBLE:View.GONE);
        }else {
            holder.lin.setVisibility(View.GONE);
        }
        holder.checkBox.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (holder.checkBox.isChecked()){
                    MainActivity.map.put(tag,true);
                }else {
                    MainActivity.map.put(tag,false);
                }
            }
        });

        holder.container.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (holder.lin.isShown()){
                    holder.lin.setVisibility(View.GONE);
                    MainActivity.isShown.put(tag,View.GONE);
                }else {
                    holder.lin.setVisibility(View.VISIBLE);
                    MainActivity.isShown.put(tag,View.VISIBLE);
                }
            }
        });

    }
item布局文件:

<?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="wrap_content"
    android:id="@+id/ll_container"
    android:descendantFocusability="blocksDescendants"
    android:orientation="vertical">

    <CheckBox
        android:id="@+id/cb_my"
        android:layout_width="wrap_content"
        android:layout_height="match_parent"
        android:button="@null"
        android:drawableLeft="@drawable/check_box_style"
        android:drawablePadding="5dp"
        android:padding="5dp" />

    <LinearLayout
        android:id="@+id/ll"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        android:visibility="gone">
        <TextView
            android:id="@+id/tv"
            android:layout_width="wrap_content"
            android:text="隐藏的信息"
            android:layout_height="wrap_content" />
    </LinearLayout>
</LinearLayout>

参考文章:

1、Recycleview checkbox 复用出现混乱解决方法:http://blog.csdn.net/fangchao3652/article/details/44103945

2、完美解决ListView和CheckBox焦点冲突及复用时CheckBox错位等一系列问题:http://blog.csdn.net/zhangjinhuang/article/details/49561893

第二篇文章介绍了:解决ListView和CheckBox焦点冲突;CheckBox的选择、全选、反选、删除的实现;下拉刷新,上拉加载checkbox的选中错位等问题。

  • 0
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值