如何將多個選擇新增到Android RecyclerView
該 RecyclerView
小部件是當今大多數Android應用程式不可或缺的一部分。自從2014年末它被新增到Android支援庫以來,它已經將 ListView
小部件作為顯示大型複雜列表的首選小部件而黯然失色。但是,缺少一個重要的功能:支援選擇和跟蹤列表項。 RecyclerView Selection 是谷歌今年3月釋出的一個外掛庫,試圖解決這個問題。
在本教程中,我將向您展示如何使用新庫建立一個應用程式,該應用程式提供了一個直觀的介面,用於選擇列表中的多個專案。按照此Android RecyclerView多選示例,您將學習一些可以在自己的應用中應用的技能。
先決條件
要跟進,您需要:
- 最新版本的 Android Studio
- 執行Android API級別23或更高級別的裝置或模擬器
1.新增RecyclerView Android依賴項
要將RecyclerView Selection庫新增到Android Studio專案,請 implementation
在 app
模組的 build.gradle 檔案中提及以下依賴 項 :
1.implementation 'com.android.support:recyclerview-v7:28.0.0' 2.implementation 'com.android.support:recyclerview-selection:28.0.0'
2.建立一個列表
在本教程中,我們將使用一小部分專案,每個專案都包含一個人的姓名和電話號碼。
要儲存每個列表項的資料,請建立一個名為的Kotlin資料類,Person併為其新增兩個屬性:name 和phone。
1.data class Person(val name:String, 2.val phone: String)
您現在可以繼續Person 在主活動中建立物件列表。
val myList = listOf( Person("Alice", "555-0111"), Person("Bob", "555-0119"), Person("Carol", "555-0141"), Person("Dan", "555-0155"), Person("Eric", "555-0180"), Person("Craig", "555-0145") )
3.將Recycler檢視新增到佈局
當然,我們將使用RecyclerView 小部件來顯示列表。因此<RecyclerView> ,在主活動的佈局XML檔案中新增 標記。
<android.support.v7.widget.RecyclerView android:layout_width="match_parent" android:layout_height="match_parent" android:id="@+id/my_rv"> </android.support.v7.widget.RecyclerView>
要指定列表項的佈局,請建立一個新的XML檔案並將其命名為list_item.xml。在其中,新增兩個TextView 小部件:一個用於顯示名稱,另一個用於顯示電話號碼。如果使用LinearLayout 元素來定位視窗小部件,則XML檔案的內容應如下所示:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="wrap_content" android:padding="16dp"> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:id="@+id/list_item_name" style="@style/TextAppearance.AppCompat.Large"/> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:id="@+id/list_item_phone" style="@style/TextAppearance.AppCompat.Small"/> </LinearLayout>
4.建立一個View Holder
您可以將檢視持有者視為一個物件,其中包含對列表項佈局中存在的檢視的引用。沒有它,RecyclerView 視窗小部件將無法有效地呈現列表項。
現在,您需要一個檢視持有者,它包含TextView 您在上一步中建立的兩個小部件。因此,建立一個擴充套件RecyclerView.ViewHolder 類的新類,並初始化對其中的小部件的引用。這是如何做:
class MyViewHolder(view: View) : RecyclerView.ViewHolder(view) { val name: TextView = view.list_item_name val phone: TextView = view.list_item_phone // More code here }
此外,RecyclerView Selection外掛需要一種可以呼叫以唯一標識所選列表項的方法。理想情況下,此方法屬於檢視持有者本身。此外,它必須返回ItemDetailsLookup.ItemDetails 類的例項。因此,請將以下程式碼新增到檢視持有者:
fun getItemDetails(): ItemDetailsLookup.ItemDetails<Long> = object: ItemDetailsLookup.ItemDetails<Long>() { // More code here }
您現在必須覆蓋ItemDetails 類中存在的兩個抽象方法。首先重寫getPosition() 方法並返回adapterPosition 檢視持有者的屬性。該adapterPosition 屬性通常只是列表項的索引。
override fun getPosition(): Int = adapterPosition
接下來,覆蓋該getSelectionKey() 方法。此方法必須返回可用於唯一標識列表項的鍵。為了簡單起見,讓我們返回itemId 檢視持有者的 屬性。
override fun getSelectionKey(): Long? = itemId
您可以自由地使用任何其他技術來生成選擇鍵,只要它生成唯一值即可。
5.處理使用者接觸
為使RecyclerView Selection外掛正常工作,每當使用者觸控 RecyclerView 視窗小部件時,您必須將觸控的座標轉換為 ItemDetails 物件。
建立一個擴充套件ItemDetailsLookup 該類的新類,併為其新增一個建構函式,該建構函式可以接受該RecyclerView 小部件作為引數。請注意,由於該類是抽象的,因此Android Studio將自動為其抽象方法生成存根。
class MyLookup(private val rv: RecyclerView) : ItemDetailsLookup<String>() { override fun getItemDetails(event: MotionEvent) : ItemDetails<String>? { // More code here } }
正如您在上面的程式碼中看到的,該getItemDetails() 方法接收一個 MotionEvent 物件。通過將事件的X和Y座標傳遞給 findChildViewUnder() 方法,您可以確定與使用者觸控的列表項關聯的檢視。要將View物件轉換為ItemDetails 物件,您只需呼叫該getItemDetails() 方法即可。這是如何做:
val view = rv.findChildViewUnder(event.x, event.y) if(view != null) { return (rv.getChildViewHolder(view) as MyViewHolder) .getItemDetails() } return null
6.建立介面卡
您現在需要一個可以將列表繫結到RecyclerView 視窗小部件的介面卡。要建立一個,請建立一個擴充套件RecyclerView.Adapter 該類的新類。由於介面卡需要訪問列表和活動的上下文,因此新類必須具有可以同時接受兩者作為引數的建構函式。
class MyAdapter(private val listItems:List<Person>, private val context: Context) : RecyclerView.Adapter<MyViewHolder>() { }
明確指出此介面卡的每個專案將具有型別的唯一穩定識別符號非常重要Long。最好的地方是在一個init 街區內。
init { setHasStableIds(true) }
此外,為了能夠使用專案的位置作為其唯一識別符號,您必須覆蓋該 getItemId() 方法。
override fun getItemId(position: Int): Long { return position.toLong() }
因為RecyclerView.Adapter 該類是抽象的,所以您現在必須重寫另外三種方法才能使您的介面卡可用。
首先,重寫getItemCount() 方法以返回列表的大小。
override fun getItemCount(): Int = listItems.size
接下來,覆蓋該onCreateViewHolder() 方法。此方法必須返回您在本教程前面建立的檢視持有者類的例項。要建立這樣的例項,必須呼叫類的建構函式並將列表項的膨脹佈局傳遞給它。要擴展布局,請使用 類的inflate() 方法LayoutInflater。這是如何做:
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder = MyViewHolder( LayoutInflater.from(context) .inflate(R.layout.list_item, parent, false) )
最後,重寫該onBindViewHolder() 方法並適當地初始化 檢視持有者中存在text 的兩個TextView小部件的 屬性。
override fun onBindViewHolder(vh: MyViewHolder, position: Int) { vh.name.text = listItems[position].name vh.phone.text = listItems[position].phone }
7.顯示列表
此時,您幾乎擁有了渲染列表所需的一切。但是,您仍必須指定列表項的定位方式。現在,讓我們使用LinearLayoutManager 例項將它們置於另一個之下。
為了獲得最佳效能,我建議您還指出RecyclerView 視窗小部件的大小 在執行時不會更改。
將以下程式碼新增到主要活動:
my_rv.layoutManager = LinearLayoutManager(this) my_rv.setHasFixedSize(true)
最後,將介面卡的新例項分配給 視窗小部件的adapter 屬性 RecyclerView。
val adapter = MyAdapter(myList, this) my_rv.adapter = adapter
如果您現在執行您的應用程式,您將能夠看到該列表。

應用程式顯示列表
8.建立選擇跟蹤器
該 RecyclerView
外掛還不允許你選擇的任何專案。要啟用多專案選擇,您需要 SelectionTracker
在活動中使用一個物件。
private var tracker: SelectionTracker<Long>? = null
您可以使用SelectionTracker.Builder 該類初始化跟蹤器。對於其建構函式,您必須傳遞選擇ID,RecyclerView 視窗小部件,金鑰提供程式,專案詳細資訊查詢類和儲存策略。
您可以自由使用任何字串作為選擇ID。作為金鑰提供者,您可以使用StableIdKeyProvider 該類的例項。
RecyclerView選擇庫提供了各種儲存策略,所有這些策略都可確保在使用者裝置旋轉時或Android系統在資源緊張期間關閉您的應用時不會取消選擇所選專案。目前,由於選擇鍵的型別是Long,您必須使用StorageStrategy 型別的物件Long。
一旦Builder 準備就緒,你可以呼叫它的withSelectionPredicate() 方法來指定你要多少專案以允許使用者選擇。為了支援多項選擇,作為方法的引數,必須傳遞 方法SelectionPredicate 返回的 物件createSelectAnything()。
因此,在activity的onCreate() 方法中新增以下程式碼:
tracker = SelectionTracker.Builder<Long>( "selection-1", my_rv, StableIdKeyProvider(my_rv), MyLookup(my_rv), StorageStrategy.createLongStorage() ).withSelectionPredicate( SelectionPredicates.createSelectAnything() ).build()
要充分利用儲存策略,必須始終嘗試恢復onCreate() 方法內部跟蹤器的狀態。
if(savedInstanceState != null) tracker?.onRestoreInstanceState(savedInstanceState)
同樣,您必須確保在活動的onSaveInstanceState() 方法中儲存跟蹤器的狀態 。
override fun onSaveInstanceState(outState: Bundle?) { super.onSaveInstanceState(outState) if(outState != null) tracker?.onSaveInstanceState(outState) }
除非與介面卡關聯,否則選擇跟蹤器不是很有用。因此,通過呼叫setTracker() 方法將其傳遞給介面卡。
adapter.setTracker(tracker)
該setTracker() 方法尚不存在,因此在介面卡類中新增以下程式碼:
private var tracker: SelectionTracker<Long>? = null fun setTracker(tracker: SelectionTracker<Long>?) { this.tracker = tracker }
如果您此時嘗試執行應用程式,則可以在列表中選擇專案。通過長按列表項進入多項選擇模式,您將能夠在大多數裝置上感受到短暫的振動。但是,由於所選專案目前與未選擇的專案無法區分,因此您將沒有視覺反饋。要解決此問題,您需要onBindViewHolder() 在介面卡的方法內進行一些更改。
突出顯示所選專案的傳統方法是更改其背景顏色。因此,您現在必須更改LinearLayout 專案佈局XML檔案中存在的視窗小部件的背景顏色。要獲取對它的引用,請獲取TextView 對檢視持有者中可用的其中一個小部件的父級的引用。
在onBindViewHolder() 方法結束之前新增以下程式碼:
val parent = vh.name.parent as LinearLayout // More code here
接下來,您可以呼叫 物件的isSelected() 方法SelectionTracker來確定是否選擇了專案。
以下程式碼顯示如何將所選專案的背景顏色更改為青色:
if(tracker!!.isSelected(position.toLong())) { parent.background = ColorDrawable( Color.parseColor("#80deea") ) } else { // Reset color to white if not selected parent.background = ColorDrawable(Color.WHITE) }
如果您現在執行該應用程式,您應該能夠看到您選擇的專案。

應用程式顯示所選專案的列表
9.建立選擇觀察者
通常,您希望向使用者顯示當前選擇的專案數。使用RecyclerView Selection庫,這樣做非常簡單。
SelectionObserver
通過呼叫 addObserver()
方法將物件與選擇跟蹤器相關聯 。在 onSelectionChanged()
觀察者的方法內,您可以檢測所選專案數的變化。
tracker?.addObserver( object: SelectionTracker.SelectionObserver<Long>() { override fun onSelectionChanged() { val nItems:Int? = tracker?.selection?.size() // More code here } })
如何顯示所選專案的數量取決於您。目前,我建議您直接在活動的操作欄中顯示該號碼。(可選)您還可以更改操作欄的背景顏色,以便讓使用者知道列表中有活動選擇。以下程式碼顯示瞭如何:
if(nItems!=null && nItems > 0) { // Change title and color of action bar title = "$nItems items selected" supportActionBar?.setBackgroundDrawable( ColorDrawable(Color.parseColor("#ef6c00"))) } else { // Reset color and title to default values title = "RVSelection" supportActionBar?.setBackgroundDrawable( ColorDrawable(getColor(R.color.colorPrimary))) }
如果再次執行該應用程式,您現在應該看到標題更改以反映您選擇的列表項的數量。

應用程式顯示所選專案的計數
結論
在本教程中,您學習瞭如何使用RecyclerView Selection外掛庫為 RecyclerView
視窗小部件新增簡單的專案選擇支援。您還學習瞭如何動態更改所選專案的外觀,以便使用者可以將它們與未選擇的專案區分開來。
想學習更多Android知識,或者獲取相關資料請加入Android技術開發交流2群:935654177。本群可免費獲取Gradle,RxJava,小程式,Hybrid,移動架構,NDK,React Native,效能優化等技術教程!

FMNX`NW45P@2{~8XII3B4VF.png