Android5.x:RecycleView(二):单选 、多选、item背景色

改变CheckBox的效果

方式一:(一般做法)
点击item后,改变数据中的checked的值,在调用adapter.notifyDataSetChanged();或者adapter.notifyItemChanged(position);更新页面。前者更耗内存。

adapter.setOnItemClickListener(new SingleChoiceRecyAdapter.OnItemClickListener() {
    @Override
    public void onItemClick(View view, int position) {
        for (int i = 0; i < list.size(); i++) {
             list.get(i).setChecked(false);
        }
        list.get(position).setChecked(true);
        adapter.notifyDataSetChanged();
    }
});

方式二:(性能消耗低)
点击item后,先获取view对应的ViewHolder,再改变数据中checked的值,再修改CheckBox的状态。不需要调用adapter.notifyDataSetChanged();或者adapter.notifyItemChanged(position);

adapter.setOnItemClickListener(new MulipleRecyAdapter.OnItemClickListener() {
    @Override
    public void onItemClick(View view, int position) {

        MulipleRecyAdapter.MyHolder holder = (MulipleRecyAdapter.MyHolder) recyclerView.getChildViewHolder(view);

        Person person = list.get(position);
        person.setChecked(!person.isChecked());
        holder.checkBox.setChecked(person.isChecked());
    }
});

怎么获取多选中选中的数据?

方法一:(这种比较麻烦,有时候会出问题,不推荐)
RecyclerView点击时用List记录对应的position

adapter.setOnItemClickListener(new BgMultipleChoiceRecyAdapter.OnItemClickListener() {
    @Override
    public void onItemClick(View view, int position) {
    ...
    if (!posiList.contains(position ) && itemView.isChecked()) {
        posiList.add(position);
    } else if (posiList.contains(position) || !itemView.isChecked()) {
        posiList.remove(posiList.indexOf(position ));
    }
}

方法二:(一般做法)
for遍历整个数据集合,找出checked==trueposition

StringBuffer sb = new StringBuffer();
for (int i = 0; i < list.size(); i++) {
    if (list.get(i).isChecked()) {
        sb.append(list.get(i).getName() + ",");
    }
}

怎么获取item的ViewHolder

正确:

recyclerView.getChildViewHolder(view);

错误

(MyHolder) view.getTag();

这里写图片描述

单选

单选都是通过标志位实现的,就是给bean添加Boolean属性,标明是否选中。

public class Person {
    private String name;
    private int age;
    private boolean checked;//是否选中
    ...
}

单选:按钮

RecyclerView的item点击事件中,改变标识位,调用notifyDataSetChanged()刷新页面

效果图:

这里写图片描述

RecyclerView在xml中的布局

<android.support.v7.widget.RecyclerView
    android:id="@+id/recyclerView"
    android:layout_width="match_parent"
    android:layout_height="match_parent"/>

item_single_choice

<?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="60dp"
              android:gravity="center_vertical"
              android:orientation="horizontal">

    <RadioButton
        android:id="@+id/rb"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        />

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginLeft="20dp"
        android:orientation="vertical">

        <TextView
            android:id="@+id/tv1"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="tv1"/>

        <TextView
            android:id="@+id/tv2"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="tv2"/>
    </LinearLayout>

</LinearLayout>

SingleChoiceRecyAdapter中使用标志位

@Override
public void onBindViewHolder(RecyclerView.ViewHolder viewHolder, final int position) {
    MyHolder holder = (MyHolder) viewHolder;
    Person person = list.get(position);

    holder.rb1.setChecked(person.isChecked());
    holder.tv1.setText("姓名:" + person.getName());
    holder.tv2.setText("年龄:" + person.getAge());

    if (onItemClickListener != null) {
        holder.itemView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                onItemClickListener.onItemClick(view, position);
            }
        });
    }
}

在item的点击事件中根据标识位改变按钮

adapter.setOnItemClickListener(new SingleChoiceRecyAdapter.OnItemClickListener() {
    @Override
    public void onItemClick(View view, int position) {
        Log.d(TAG, "position=" + position);

        for (int i = 0; i < list.size(); i++) {
            if (i == position ) {
                list.get(i).setChecked(true);//必须选择一个
            } else {
                list.get(i).setChecked(false);
            }
        }
        checkedPosition = position;
        adapter.notifyDataSetChanged();
    }
});

获取选中的item的pisition

btn.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View view) {
        Log.d(TAG, "单选的position=" + checkedPosition);
        Toast.makeText(SingleChoiceActivity.this, ""+checkedPosition, Toast.LENGTH_SHORT).show();
    }
});

单选:item背景色

效果图

这里写图片描述

改变item的背景色,需要重写item的根布局,并实现接口Checkable

ChoiceItemLayout ###:

public class ChoiceItemLayout extends LinearLayout implements Checkable {

    private boolean mChecked;
    public ChoiceItemLayout(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
    }

    @Override
    public void setChecked(boolean checked) {
        mChecked = checked;
        setBackgroundResource(checked? R.color.colorAccent : android.R.color.transparent);
    }

    @Override
    public boolean isChecked() {
        return true;
    }

    @Override
    public void toggle() {
        setChecked(!mChecked);
    }
}

item_bg_choice.xml

ChoiceItemLayout作为根布局

<?xml version="1.0" encoding="utf-8"?>
<com.qihu.recyclerviewchoice.view.ChoiceItemLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="60dp"
    android:gravity="center_vertical"
    android:orientation="horizontal">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginLeft="20dp"
        android:orientation="vertical">

        <TextView
            android:id="@+id/tv1"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="tv1"/>

        <TextView
            android:id="@+id/tv2"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="tv2"/>
    </LinearLayout>

</com.qihu.recyclerviewchoice.view.ChoiceItemLayout>

根据标志位实现背景色的变化

@Override
public void onBindViewHolder(RecyclerView.ViewHolder viewHolder, final int position) {
    MyHolder holder = (MyHolder) viewHolder;

    ChoiceItemLayout layout = (com.qihu.recyclerviewchoice.view.ChoiceItemLayout) holder.itemView;
    layout.setChecked(person.isChecked());
    ...
}

在item的点击事件中根据标识位更新背景色

adapter.setOnItemClickListener(new BgSingleChoiceRecyAdapter.OnItemClickListener() {
    @Override
    public void onItemClick(View view, int position) {
        Log.d(TAG, "position=" + position);

        for (int i = 0; i < list.size(); i++) {
            if (i == position) {
                list.get(i).setChecked(true);
            } else {
                list.get(i).setChecked(false);
            }
        }
        checkedPosition = position;
        adapter.notifyDataSetChanged();
    }
});

获取选中的item的position

btn.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View view) {
        Log.d(TAG, "单选=" + checkedPosition);
        Toast.makeText(BgSingleChoiceActivity.this, "" + checkedPosition, Toast.LENGTH_SHORT).show();
    }
});

单选:带有HeadView和FootView

这里写图片描述
加了头尾布局个一个,这就要求我们在改变item的标识位时注意正确的position

adapter.setOnItemClickListener(new SingleChoiceHeadFootAdapter.OnItemClickListener() {
    @Override
    public void onItemClick(View view, int position) {
        Log.d(TAG, "position=" + position);

        for (int i = 0; i < list.size(); i++) {
            if (i == position - adapter.getHeadViewCount()) {//注意
                list.get(i).setChecked(true);
            } else {
                list.get(i).setChecked(false);
            }
        }
        checkedPosition = position- adapter.getHeadViewCount();//注意
        adapter.notifyDataSetChanged();
    }
});

添加头尾布局也在本篇博客。
包含头尾的adapter

public class SingleChoiceHeadFootAdapter extends RecyclerView.Adapter {

    private View headView;
    private View footView;
    public static final int HEAD = 1;
    public static final int NORMAL = 2;
    public static final int FOOT = 3;
    public List<Person> list;

    public SingleChoiceHeadFootAdapter(List<Person> list) {
        this.list = list;
    }


    public void addHeadView(View headView) {
        this.headView = headView;
    }

    public void addFootView(View footView) {
        this.footView = footView;
    }

    public int getHeadViewCount() {
        return headView == null ? 0 : 1;
    }

    public int getFootViewCount() {
        return footView == null ? 0 : 1;
    }

    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        if (viewType == HEAD) {
            return new MyHolder(headView);
        }
        if (viewType == FOOT) {
            return new MyHolder(footView);
        }

        View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_single_choice, parent, false);
        return new MyHolder(view);
    }

    @Override
    public void onBindViewHolder(RecyclerView.ViewHolder viewHolder, final int position) {
        if (getItemViewType(position) == HEAD) {
            return;
        }
        if (getItemViewType(position) == FOOT) {
            return;
        }

        MyHolder holder = (MyHolder) viewHolder;
        Person person = list.get(position - getHeadViewCount());

        holder.rb.setChecked(person.isChecked());
        holder.tv1.setText("姓名:"+person.getName());
        holder.tv2.setText("年龄:"+person.getAge());

        if (onItemClickListener != null) {
            holder.itemView.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    onItemClickListener.onItemClick(view, position);
                }
            });
        }
    }

    @Override
    public int getItemCount() {
        return list.size() + getHeadViewCount() + getFootViewCount();
    }

    @Override
    public int getItemViewType(int position) {
        if (position < getHeadViewCount()) {
            return HEAD;
        }
        if (position >= list.size() + getHeadViewCount()) {
            return FOOT;
        }
        return NORMAL;
    }


    public class MyHolder extends RecyclerView.ViewHolder {

        public RadioButton rb;
        public TextView tv1;
        public TextView tv2;

        public MyHolder(View itemView) {
            super(itemView);
            if (itemView == headView) {
                return;
            }
            if (itemView == footView) {
                return;
            }
            rb = (RadioButton) itemView.findViewById(R.id.rb);
            tv1 = (TextView) itemView.findViewById(R.id.tv1);
            tv2 = (TextView) itemView.findViewById(R.id.tv2);
        }
    }


    public interface OnItemClickListener {
        void onItemClick(View view, int position);
    }

    private OnItemClickListener onItemClickListener;

    public void setOnItemClickListener(OnItemClickListener onItemClickListener) {
        this.onItemClickListener = onItemClickListener;
    }
}

添加HeaderView和FooterView

View headView = LayoutInflater.from(this).inflate(R.layout.layout_header, recyclerView, false);
View footView = LayoutInflater.from(this).inflate(R.layout.layout_footer, recyclerView, false);
adapter.addHeadView(headView);
adapter.addFootView(footView);

多选

多选:框

RecyclerView的item点击事件中,根据view获取ViewHolder,在获取CheckBox,调用toggle()

多选还是应该用标志位来解决。下面代码有的没加入标志位,demo中修复了。下面的搞复杂了,可以不用看了,直接用常用的标识位就可以了。

效果图

这里写图片描述

代码

adapter.setOnItemClickListener(new MulipleRecyAdapter.OnItemClickListener() {
    @Override
    public void onItemClick(View view, int position) {
        MulipleRecyAdapter.MyHolder holder = (MulipleRecyAdapter.MyHolder) recyclerView.getChildViewHolder(view);

        Person person = list.get(position);
        person.setChecked(!person.isChecked());
        holder.checkBox.setChecked(person.isChecked());
    }
});

adapter

@Override
public void onBindViewHolder(RecyclerView.ViewHolder viewHolder, final int position) {
    MyHolder holder = (MyHolder) viewHolder;
    Person person = list.get(position);

    holder.checkBox.setChecked(person.isChecked());
    holder.tv1.setText("姓名:" + person.getName());
    holder.tv2.setText("年龄:" + person.getAge());

    if (onItemClickListener != null) {
        holder.itemView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                onItemClickListener.onItemClick(view, position);
            }
        });
    }
}

多选:改变item背景色

同单选一样,改变item的背景色,必须重写item的根布局,并实现接口Checkable

效果图

这里写图片描述

ChoiceItemLayout

public class ChoiceItemLayout extends LinearLayout implements Checkable {

    private boolean mChecked;
    public ChoiceItemLayout(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
    }

    @Override
    public void setChecked(boolean checked) {
        mChecked = checked;
        setBackgroundResource(checked? R.color.colorAccent : android.R.color.transparent);
    }

    @Override
    public boolean isChecked() {
        return true;
    }

    @Override
    public void toggle() {
        setChecked(!mChecked);
    }
}

adapter

@Override
public void onBindViewHolder(RecyclerView.ViewHolder viewHolder, final int position) {
    MyHolder holder = (MyHolder) viewHolder;
    Person person = list.get(position);
    ((ChoiceItemLayout)(holder.itemView)).setChecked(person.isChecked());
     ...
}

在adapter的item的点击事件中改变背景色+修改数据标志位

adapter.setOnItemClickListener(new BgMultipleChoiceRecyAdapter.OnItemClickListener() {
    @Override
    public void onItemClick(View view, int position) {
        Log.d(TAG, "position=" + position);

        BgMultipleChoiceRecyAdapter.MyHolder holder = (BgMultipleChoiceRecyAdapter.MyHolder) recyclerView.getChildViewHolder(view);
        ChoiceItemLayout itemView = (ChoiceItemLayout) holder.itemView;
        //先改数据,再改变背景色
        Person person = list.get(position);
        person.setChecked(!person.isChecked());

        itemView.setChecked(person.isChecked());
    }
});

取出选中的item的position

StringBuffer sb = new StringBuffer();
for (int i = 0; i < list.size(); i++) {
     Person person = list.get(i);
     if (person.isChecked()) {
         sb.append(person.getName() + ",");
     }
 }

多选:带有HeaderView和FooterView

效果图

这里写图片描述

主要是注意下标识位的position

adapter.setOnItemClickListener(new MultipleChoiceHeadFootAdapter.OnItemClickListener() {
    @Override
    public void onItemClick(View view, int position) {
        Log.d(TAG, "position=" + position);

        MultipleChoiceHeadFootAdapter.MyHolder holder = (MultipleChoiceHeadFootAdapter.MyHolder) recyclerView.getChildViewHolder(view);
        holder.checkBox.toggle();
        list.get(position-1).setChecked(holder.checkBox.isChecked());
    }
});

为什么不能像ListView那样给item使用xml属性:duplicateParentState

经测试无效,ListView本身还设置了android:choiceMode=“”属性,但是RecyclerView乜有这个属性,也没有方法listView.getCheckItemIds();

其他

Demo : https://git.oschina.net/RecyclerView/RecyclerViewChecked01
apk下载地址:http://fir.im/gb3x

Android5.x:RecycleView(一):实现ListView + GridView + StaggeredGridLayou效果
Android5.x:RecycleView(二):单选 、多选、item背景色
Android5.x:RecycleView(三):上下拖动和左右滑动删除

  • 5
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 6
    评论
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值