Foreword
We often encounter the need for single selection in the list. The previous approach was ItemBean
to add a boolean
type isSelected
field to our data source and Adapter
determine the selected state based on this field. Each time you select a new one item
, change the i sSelected
field in the data source and call to notifyDataSetChanged()
refresh the entire list. This is relatively simple to implement, but if there are too many entries in the list, it will get stuck slightly. This article will be implemented in another way, relatively elegant
Implementation plan
First we look at the renderings
Here we use RecyclerView
the findViewHolderForLayoutPosition()
method, which will get a postion
of ViewHolder
, but please note that the return value may be empty, when used require special care, it means empty screen sight
We first define the data sourceItemBean
**
* @author HuangFusheng
* @date 2019-11-11
* description 列表的Item数据
*/
public class ItemBean {
private String name;
private boolean isSelected;
public ItemBean(String name) {
this.name = name;
}
public ItemBean(String name, boolean isSelected) {
this.name = name;
setSelected(isSelected);
}
public boolean isSelected() {
return isSelected;
}
public void setSelected(boolean selected) {
isSelected = selected;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
There is also one in it isSelected
, but we will not use this field as in the preface.We just use it to indicate whether it is selected.Next
we will write our most important.The Adapter
basic definition implementation will not be explained in detail here. We only talk about the more important things, the other is to look at the code.
The first step: Adapter
define a variable in our mSelectedPos
, which represents our currently selected position, when we click on the other Item
, we will mSelectedPos
change this to that Item
one position
, and it is estimated that we understand the principle we want to achieve here, we The core idea is to refresh two changes directionally Item
, one is originally selected, and the other is what we clicked. In this case, only the changed part is changed, and the onBindViewHolder()
method will not be repeated .
The second step: we get initialized Adapter
by the isSelected
field in our constructormSelectedPos
public ItemAdapter(List<ItemBean> datas, Context context, RecyclerView rv) {
mDatas = datas;
mContext = context;
mInflater = LayoutInflater.from(mContext);
mRv = rv;
//找到默认选中的position
for (int i = 0; i < mDatas.size(); i++) {
if (mDatas.get(i).isSelected()) {
mSelectedPos = i;
}
}
}
Step 3: When we click Item
, findViewHolderForLayoutPosition()
get the mSelectedPos
corresponding through this method ViewHolder
, Item
set the control in this item to unchecked, then assign position
the value of the click mSelectedPos
, and then position
set the position control to the selected state, operation At the same time we also need to change the state of the data source
holder.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
ViewHolder viewHolder = (ViewHolder) mRv.findViewHolderForLayoutPosition(mSelectedPos);
//表示还在屏幕里
if (viewHolder != null) {
viewHolder.ivSelect.setSelected(false);
} else {
notifyItemChanged(mSelectedPos);
}
//改变数据状态
mDatas.get(mSelectedPos).setSelected(false);
//设置新Item的勾选状态
mSelectedPos = position;
mDatas.get(mSelectedPos).setSelected(true);
holder.ivSelect.setSelected(true);
}
});
Ok, here we are done, paste the complete Adapter
code
/**
* @author HuangFusheng
* @date 2019-11-11
* description 适配器
*/
public class ItemAdapter extends RecyclerView.Adapter<ItemAdapter.ViewHolder> {
private static final String TAG = "ItemAdapter";
private List<ItemBean> mDatas;
private Context mContext;
private LayoutInflater mInflater;
/**
* 当前选中的位置
*/
private int mSelectedPos = -1;
private RecyclerView mRv;
public ItemAdapter(List<ItemBean> datas, Context context, RecyclerView rv) {
mDatas = datas;
mContext = context;
mInflater = LayoutInflater.from(mContext);
mRv = rv;
//找到默认选中的position
for (int i = 0; i < mDatas.size(); i++) {
if (mDatas.get(i).isSelected()) {
mSelectedPos = i;
}
}
}
@NonNull
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View itemView = mInflater.inflate(R.layout.item_layout, parent, false);
return new ViewHolder(itemView);
}
@Override
public void onBindViewHolder(final ViewHolder holder, final int position) {
Log.e(TAG, "执行onBindViewHolder: .....");
holder.ivSelect.setSelected(mDatas.get(position).isSelected());
holder.tvName.setText(mDatas.get(position).getName());
holder.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
ViewHolder viewHolder = (ViewHolder) mRv.findViewHolderForLayoutPosition(mSelectedPos);
//表示还在屏幕里
if (viewHolder != null) {
viewHolder.ivSelect.setSelected(false);
} else {
notifyItemChanged(mSelectedPos);
}
//改变数据状态
mDatas.get(mSelectedPos).setSelected(false);
//设置新Item的勾选状态
mSelectedPos = position;
mDatas.get(mSelectedPos).setSelected(true);
holder.ivSelect.setSelected(true);
}
});
}
@Override
public int getItemCount() {
return null != mDatas ? mDatas.size() : 0;
}
public static class ViewHolder extends RecyclerView.ViewHolder {
private ImageView ivSelect;
private TextView tvName;
public ViewHolder(View itemView) {
super(itemView);
ivSelect = (ImageView) itemView.findViewById(R.id.iv_item_select);
tvName = (TextView) itemView.findViewById(R.id.tv_item_name);
}
}
}
Here we operate, switch a few Item
to see if the onBindViewHolder()()
method will be executed multiple times
We see that we will not execute this method many times onBindViewHolder()
, and friends can try