記錄RecyclerView+CheckBox實現單選操作

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"就是讓父控件直接主持當前點擊事件*

效果如下


在這裏插入圖片描述-
這兩種用法瞭解了,在線考試系統也就會做了

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章