改变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());
}
});
怎么获取多选中选中的数据?
方法一:(这种比较麻烦,有时候会出问题,不推荐)
RecyclerV
iew点击时用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==true
的position
。
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(三):上下拖动和左右滑动删除