راهنمایی برای RecyclerView Selection در اندروید

مدتی بود برای پروژه ای دنبال روشی می‌گشتم تا بتونم multi selection رو برای recyclerView پیاده کنم اما آموزش هایی که توی وب پیدا کردم یا پیچیده پیاده‌سازی شده بودن یا به زبان کاتلین نوشته شده بودن که خوندنش برام به راحتی جاوا نبود.در نهایت بعد از چند روز سر و کله زدن با نمونه کد های مختلف موفق شدم به نتیجه ای که می‌خوام برسم و به نظرم اومد پستی دربارش بنویسم. امیدوارم که مفید واقع بشه. برای این آموزش ما قراره از کتابخونه ای که خود اندروید ارائه داده استفاده کنیم که داکیومنت های مربوط بهش رو میتونید اینجا ببینید.توصیه می‌کنم از AndroidX استفاده کنید برای اینکار از این مسیر اقدام کنید : Refactor > Migrate to AndroidXدو خط زیر رو به (build.gradle (Module App پروژتون اضافه کنید و sync رو بزنید.implementation 'com.google.android.material:material:1.0.0' implementation 'androidx.recyclerview:recyclerview-selection:1.0.0'خب بعد از اینکه آماده سازی های بالا رو انجام دادین اولین قدم ساختن یک recyclerView هست. با فرض اینکه پیاده سازی اون رو بلد هستین (اگر نه اینجا رو کلیک کنید) من فقط خلاصه ای از مراحل رو می‌نویسم.پیاده‌سازی RecyclerViewساخت مدل.ساخت layout به عنوان view هر سطر.ساخت کلاس ViewHolder (در اینجا من این کلاس رو به صورت inner class داخل Adapter تعریف نکردم برای اینکه تفکیک شده تر باشه و خوانایی بهتری داشته باشه).ساخت Adapter.کانفیگ کردن recyclerView و Adapter داخل MainActivity.تا اینجا اگر از اپ اجرا بگیرین باید یه recyclerView ساده مشابه عکس بالا داشته باشین.پیاده‌سازی Selectionاولین قدم تعیین نوع selection key هست که مشخص کردن آیتم های انتخاب شده رو بر عهده داره; میتونید از سه نوع parcelable , long , string استفاده کنید که من اینجا از long استفاده کردم.متد getViewHolderItemDetailspublic ItemDetailsLookup.ItemDetails<Long> getViewHolderItemDetails() { return new ItemDetailsLookup.ItemDetails<Long>() { @Override public int getPosition() { return getAdapterPosition(); } @Nullable @Override public Long getSelectionKey() { return getItemId(); } }; }این متد رو باید در ادامه کلاس ViewHolder که قبلا پیاده سازی کردین اضافه کنید. مقداری از جنس <ItemDetails<Long رو برمیگردونه که در واقع حاوی اطلاعاتی درباره ViewHolder ای هست که کاربر اون رو انتخاب کرده (شامل selection key و position هست). در ادامه قراره از اون استفاده کنیم.کلاس MyItemDetailsLookuppublic class MyItemDetailsLookup extends ItemDetailsLookup<Long> { private RecyclerView recyclerView; public MyItemDetailsLookup(RecyclerView recyclerView) { this.recyclerView = recyclerView; } @Nullable @Override public ItemDetails<Long> getItemDetails(@NonNull MotionEvent e) { View view = recyclerView.findChildViewUnder(e.getX() , e.getY()); if (view != null) { return ((ViewHolder)recyclerView.getChildViewHolder(view)) .getViewHolderItemDetails(); } return null; } }وظیفه این کلاس فراهم کردن اطلاعات درباره آیتم انتخاب شده برای استفاده کتابخانه selection هست.یک متغیر از جنس RecyclerView بگیرید و در constructor اون رو مقدار دهی کنید.متد getItemDetails رو implement کنید. این متد متغیری از جنس MotionEvent میگیره (در این مورد لمس کاربر) و با استفاده از متد getViewHolderItemDetails که در مرحله قبل نوشتیم اطلاعات View انتخاب شده توسط کاربر رو به ما برمیگردونه.کلاس ModelAdapterاین کلاس رو قبلا برای RecyclerView نوشته بودیم اما برای پیاده کردن selection باید چند متد رو بهش اضافه کنیم.خط زیر رو داخل constructor کلاس اضافه کنید.setHasStableIds(true);متد getItemId رو override کنید این متد position رو به long کست میکنه و به عنوان آیدی برمیگردونه.@Override public long getItemId(int position) { return (long)position; }متغیری از جنس <SelectionTracker<Long با نام tracker تعریف کنید و یک متد برای set کردن مقدار اون بنویسید.این متد بعدا برای پر کردن trakcer استفاده خواهد شد.SelectionTracker<Long> tracker; public void setTracker(SelectionTracker<Long> tracker) { this.tracker = tracker; }استفاده از tracker در متد onBindViewHolder برای نشان دادن آیتم های انتخاب شده توسط کاربرif (tracker != null) { //if item is selected , change the color of views if (tracker.isSelected((long)position)) { holder.nameTV.setTextColor(Color.RED); holder.phoneTV.setTextColor(Color.RED); holder.container.setBackgroundColor(Color.LTGRAY); } //if item is not selected or deselected change color to default else { holder.nameTV.setTextColor(Color.BLACK); holder.phoneTV.setTextColor(Color.BLACK); holder.container.setBackgroundColor(Color.WHITE); } }در نهایت مقدار دهی به trackerداخل اکتیویتی متغیری از جنس <SelectionTracker<Long با نام trakcer تعریف کنید.به صورت زیر به اون مقدار دهی کنید.tracker = new SelectionTracker.Builder<>("selection1" , recyclerView , new StableIdKeyProvider(recyclerView) , new MyItemDetailsLookup(recyclerView) , StorageStrategy.createLongStorage()) .withSelectionPredicate(SelectionPredicates.<Long>createSelectAnything()) .build(); //set tracker to adapter modelAdapter.setTracker(tracker);برای دیدن سورس کامل اینجا کلیک کنید.