Android中关于这个表单的操作中单选和多选操作比较多,尤其在列表中操作的这个状态值很绕脑子,还要考虑焦点冲突,滑动错乱。之前又做过购物车的多选,全选,反选;还做过考试系统的单选题和多选题除过这些常规的以外还有各种奇葩需求,多选可以参考我以前写的博客列表多选操作,今天我来记录一个电商app中选择优惠券的单选操作(一般很少让你同时使用多张优惠券)
具体代码如下,可以自行看注释
public class SingleChooseActivity extends AppCompatActivity {
private SingleChooseActivity mContext;
private List<ItemEntity> mData;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mContext = this;
init();
}
private void init() {
RecyclerView mRecyclerView = findViewById(R.id.recyclerView);
initData();
mRecyclerView.setLayoutManager(new LinearLayoutManager(mContext));
mRecyclerView.setAdapter(new MyAdapter(3));
}
private void initData() {
if (mData == null) {
mData = new ArrayList<>();
}
mData.clear();
for (int i = 0; i < 20; i++) {
ItemEntity itemEntity = new ItemEntity();
itemEntity.title = "title-" + i;
itemEntity.isChecked = false;
mData.add(itemEntity);
}
}
private class MyAdapter extends RecyclerView.Adapter<MyAdapter.MyHolder> {
/**
* 游标记录上一次选中的位置,默认为-1
*/
private int mLastIndex = -1;
public MyAdapter(int lastIndex) {
/**
* 通过构造函数设置回显数据
*/
if (lastIndex > -1 && lastIndex < mData.size()) {
this.mLastIndex = lastIndex;
mData.get(mLastIndex).isChecked = true;
}
}
@NonNull
@Override
public MyHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
return new MyHolder(View.inflate(mContext, R.layout.list_item, null));
}
@Override
public void onBindViewHolder(@NonNull final MyHolder holder, final int position) {
final ItemEntity itemEntity = mData.get(position);
if (itemEntity != null) {
//防止CheckBox复用错乱
holder.cbChecked.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
itemEntity.isChecked = holder.cbChecked.isChecked();
changeStatus(position);
}
});
holder.tvTitle.setText(itemEntity.title);
holder.cbChecked.setChecked(itemEntity.isChecked);
holder.itemView.setBackgroundResource(itemEntity.isChecked ? R.color.color_highlight : R.color.color_disabled);
holder.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
changeStatus(position);
}
});
}
}
@Override
public int getItemCount() {
return mData == null ? 0 : mData.size();
}
private void changeStatus(int position) {
ItemEntity mEntity = mData.get(position);
if (mLastIndex == -1) {
//如果mLastIndex==-1说明是第一次操作,直接选中当前项,游标 mLastIndex记录当前选中位置
mEntity.isChecked = true;
mLastIndex = position;
} else if (mLastIndex == position) {
//如果mLastIndex==position说明是反选操作,直接将当前位置的选中状态修改为false,游标 mLastIndex还原为-1
mEntity.isChecked = false;
mLastIndex = -1;
} else {
//如果mLastIndex!=position && 如果mLastIndex !=-1,说明切换选中其他条目,交换选中位置,游标 mLastIndex记录当前选中位置
mEntity.isChecked = true;
mData.get(mLastIndex).isChecked = false;
mLastIndex = position;
}
Log.d("ItemEntity---", "mLastIndex: " + mLastIndex);
for (ItemEntity mItemEntity : mData) {
Log.d("ItemEntity---", "title: " + mItemEntity.title + ",isChecked:" + mItemEntity.isChecked);
}
//更新当前列表
notifyDataSetChanged();
}
class MyHolder extends RecyclerView.ViewHolder {
TextView tvTitle;
CheckBox cbChecked;
MyHolder(@NonNull View itemView) {
super(itemView);
tvTitle = itemView.findViewById(R.id.tv_title);
cbChecked = itemView.findViewById(R.id.cb_checked);
}
}
}
class ItemEntity {
String title;
boolean isChecked;
}
}
changeStatus方法是这个业务的核心操作,我写了详细注释,以前这块业务我们一般会用到for循环遍历操作,但是考虑到性能问题,所以对算法做了优化,这个UI我直接是在Activity
中写的,如果要弹窗的话可以考虑Dialog、PopupWindow、ListPopupWindow和DialogFragment
等,或者可以给Activity
设置为Dialog模式
带上item的布局,因为这里要处理光标点击事件
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:descendantFocusability="blocksDescendants"
>
<TextView
android:id="@+id/tv_title"
android:layout_width="wrap_content"
android:layout_height="60dp"
android:layout_centerVertical="true"
android:layout_marginStart="16dp"
android:gravity="center"
android:text="标题" />
<CheckBox
android:id="@+id/cb_checked"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:layout_centerVertical="true"
android:layout_marginEnd="16dp" />
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:layout_alignParentBottom="true"
android:background="@color/colorAccent" />
</RelativeLayout>
android:descendantFocusability="blocksDescendants"
就是让父控件直接主持当前点击事件*
效果如下
-
这两种用法了解了,在线考试系统也就会做了