Create a List with RecyclerView
使用RecyclerView創(chuàng)建列表布局
If your app needs to display a scrolling list of elements based on large data sets (or data that frequently changes), you should use RecyclerView as described on this page.
如果你的APP需要顯示大量數(shù)據(jù)集合的滾動(dòng)列表布局(或者數(shù)據(jù)經(jīng)常變化),你應(yīng)該使用RecyclerView來實(shí)現(xiàn)這個(gè)頁面熟空。
*Tip: Start with some template code in Android Studio by clicking File > New > Fragment > Fragment (List). Then simply add the fragment to your activity layout.
在Android studio中通過點(diǎn)擊’文件‘->‘新建’->‘Fragment’->'Fragment(List)'.就可以簡單的添加Fragment到你的activity布局中却音。
Figure 1. A list using RecyclerView
Figure 2. A list also using CardView
If you'd like to create a list with cards, as shown in figure 2, also use the CardView widget as described in Create a Card-based Layout.
If you'd like to see some sample code for RecyclerView, check out the RecyclerView Sample App.
如果你想創(chuàng)建卡片列表,想圖2一樣易遣,你也可以使用CardView控件來實(shí)現(xiàn)卡片布局。
如果你想查看RecyclerView的代碼例子,可以點(diǎn)擊RecyclerView Sample App
RecyclerView overview
RecyclerView 概述
The RecyclerView widget is a more advanced and flexible version of ListView.
In the RecyclerView model, several different components work together to display your data. The overall container for your user interface is a RecyclerView object that you add to your layout. The RecyclerView fills itself with views provided by a layout manager that you provide. You can use one of our standard layout managers (such asLinearLayoutManager or GridLayoutManager), or implement your own.
RecyclerView 控件是更高級(jí)更靈活的ListView碴开。
在Recyclerview模塊哼鬓,不同的組件一起顯示你的數(shù)據(jù)监右。你只需要在用戶界面上添加RecycleView控件。RecyclerView會(huì)通過你提供的layout manger 來填充數(shù)據(jù)到視圖上异希〗『校可以使用(LinearLayoutManager(線性布局) 或者 GridLayoutManager(表格布局)),也可以自定義布局称簿。
The views in the list are represented by view holder objects. These objects are instances of a class you define by extending RecyclerView.ViewHolder. Each view holder is in charge of displaying a single item with a view. For example, if your list shows music collection, each view holder might represent a single album. The RecyclerViewcreates only as many view holders as are needed to display the on-screen portion of the dynamic content, plus a few extra. As the user scrolls through the list, the RecyclerView takes the off-screen views and rebinds them to the data which is scrolling onto the screen.
The view holder objects are managed by an adapter, which you create by extending RecyclerView.Adapter. The adapter creates view holders as needed. The adapter also binds the view holders to their data. It does this by assigning the view holder to a position, and calling the adapter's onBindViewHolder() method. That method uses the view holder's position to determine what the contents should be, based on its list position.
列表的view通過viewholder對(duì)象表示扣癣。這些對(duì)象是RecyclerView.ViewHolder的子類。每個(gè)view的holder負(fù)責(zé)顯示每一個(gè)view憨降。例如父虑,如果你的列表顯示音樂collection,每一個(gè)view holder 可能會(huì)表示一張專輯授药。Recyclerview 只會(huì)創(chuàng)建需要顯示與屏幕內(nèi)容需要的相同數(shù)量的viewHolder士嚎,加上幾個(gè)額外的呜魄。當(dāng)用戶滑動(dòng)列表時(shí),RecyclerView將會(huì)取消綁定一些事圖莱衩,并重新綁定到哪些滑動(dòng)進(jìn)屏幕的列表上爵嗅。
viewHolder對(duì)象由RecycleView.Adapter的子類管理。adapter通過onBindViewHolder()將viewHolder綁定到position(下標(biāo))上笨蚁,從而能在需要的時(shí)候創(chuàng)建viewHolder睹晒,并且綁定相應(yīng)的數(shù)據(jù)到view上。該方法使用viewHolder的position 來確定list中的對(duì)應(yīng)的數(shù)據(jù)括细。
This RecyclerView model does a lot of optimization work so you don't have to:
? When the list is first populated, it creates and binds some view holders on either side of the list. For example, if the view is displaying list positions 0 through 9, the RecyclerView creates and binds those view holders, and might also create and bind the view holder for position 10\. That way, if the user scrolls the list, the next element is ready to display.
? As the user scrolls the list, the RecyclerView creates new view holders as necessary. It also saves the view holders which have scrolled off-screen, so they can be reused. If the user switches the direction they were scrolling, the view holders which were scrolled off the screen can be brought right back. On the other hand, if the user keeps scrolling in the same direction, the view holders which have been off-screen the longest can be re-bound to new data. The view holder does not need to be created or have its view inflated; instead, the app just updates the view's contents to match the new item it was bound to.
? When the displayed items change, you can notify the adapter by calling an appropriate RecyclerView.Adapter.notify…() method. The adapter's built-in code then rebinds just the affected items.
RecyclerView幫你做了很多額外的工作:
當(dāng)view第一次顯示是册招,它創(chuàng)建需要顯示的viewHolder并綁定到相應(yīng)的數(shù)據(jù)上。例如勒极,如果顯示第0-9項(xiàng)是掰,RecyclerView創(chuàng)建并綁定相應(yīng)的viewHloders,也可以同時(shí)創(chuàng)建并綁定第10項(xiàng)viewHloder辱匿,如果用戶滑動(dòng)列表键痛,則下一項(xiàng)數(shù)據(jù)已經(jīng)準(zhǔn)備好可以顯示了。
當(dāng)用戶滑動(dòng)列表匾七,RecyclerView會(huì)創(chuàng)建相鄰的需要顯示的viewHolder絮短,同時(shí)會(huì)把那些已經(jīng)劃出屏幕的viewHolder保存起來,這樣用戶往回劃就能重新使用剛才的viewHolder昨忆。同時(shí)丁频,如果用戶一直在一個(gè)方向上劃,那那些最遠(yuǎn)的ViewHolder就會(huì)被拿回來重新綁定要顯示的數(shù)據(jù)邑贴。ViewHolder 并不需要?jiǎng)?chuàng)建view的inflated席里,只需要更新view的內(nèi)容去匹配到新的item上面。
當(dāng)顯示的items發(fā)生變化時(shí)拢驾,你可以通知adapter通過調(diào)用notify()方法奖磁。adapter提供的方法來重新綁定受影響的視圖。
Add the support library****(添加依賴庫)
To access the RecyclerView widget, you need to add the v7 Support Libraries to your project as follows:
要使用RecyclerView控件繁疤,需要使用以下方式引入v7Support Libraries到你的項(xiàng)目中:
dependencies {
implementation 'com.android.support:recyclerview->v7:27.1.1'
}
Add RecyclerView to your layout
Now you can add the RecyclerView to your layout file. For example, the following layout uses RecyclerView as the only view for the whole layout:
現(xiàn)在你可以添加RecyclerView到你的布局文件中咖为。例如,下面的布局使用RecyclerView作為唯一的布局在整個(gè)layout中:
<?xml version="1.0" encoding="utf-8"?>
<!-- A RecyclerView with some commonly used attributes -->
<android.support.v7.widget.RecyclerView
android:id="@+id/my_recycler_view"
android:scrollbars="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
Once you have added a RecyclerView widget to your layout, obtain a handle to the object, connect it to a layout manager, and attach an adapter for the data to be displayed:
當(dāng)你添加了RecyclerView控件到你的布局文件中稠腊,就可以并綁定到對(duì)象上躁染,連接上layoutManager,然后將數(shù)據(jù)連接到adapter上去顯示:
public class MyActivity extends Activity {
private RecyclerView mRecyclerView;
private RecyclerView.Adapter mAdapter;
private RecyclerView.LayoutManager mLayoutManager;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.my_activity);
mRecyclerView = (RecyclerView)
findViewById(R.id.my_recycler_view);
// use this setting to improve performance if you know that changes
// in content do not change the layout size of the RecyclerView
mRecyclerView.setHasFixedSize(true);
// use a linear layout manager
mLayoutManager = new LinearLayoutManager(this);
mRecyclerView.setLayoutManager(mLayoutManager);
// specify an adapter (see also next example)
mAdapter = new MyAdapter(myDataset);
mRecyclerView.setAdapter(mAdapter);
}
// ...
}
Add a list adapter
To feed all your data to the list, you must extend the RecyclerView.Adapter class. This object creates views for items, and replaces the content of some of the views with new data items when the original item is no longer visible.
The following code example shows a simple implementation for a data set that consists of an array of strings displayed using TextView widgets:
要把所有的數(shù)據(jù)添加到列表中架忌,你需要繼承RecyclerView.Adapter類吞彤,它會(huì)創(chuàng)建item的view,然后將新數(shù)據(jù)綁定到某些已經(jīng)存在但很久沒使用的view上鳖昌。
下面的代碼例子演示了如何將String數(shù)組顯示到textview控件上:
public class MyAdapter extends RecyclerView.Adapter<MyAdapter.ViewHolder> {
private String[] mDataset;
// Provide a reference to the views for each data item
// Complex data items may need more than one view per item, and
// you provide access to all the views for a data item in a view holder
public static class ViewHolder extends RecyclerView.ViewHolder {
// each data item is just a string in this case
public TextView mTextView;
public ViewHolder(TextView v) {
super(v);
mTextView = v;
}
}
// Provide a suitable constructor (depends on the kind of dataset)
public MyAdapter(String[] myDataset) {
mDataset = myDataset;
}
// Create new views (invoked by the layout manager)
@Override
public MyAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
// create a new view
TextView v = (TextView) LayoutInflater.from(parent.getContext())
.inflate(R.layout.my_text_view, parent, false);
...
ViewHolder vh = new ViewHolder(v);
return vh;
}
// Replace the contents of a view (invoked by the layout manager)
@Override
public void onBindViewHolder(ViewHolder holder, int position) {
// - get element from your dataset at this position
// - replace the contents of the view with that element holder.mTextView.setText(mDataset[position]);
}
// Return the size of your dataset (invoked by the layout manager)
@Override
public int getItemCount() {
return mDataset.length;
}
}
The layout manager calls the adapter's onCreateViewHolder() method. That method needs to construct a RecyclerView.ViewHolder and set the view it uses to display its contents. The type of the ViewHolder must match the type declared in the Adapter class signature. Typically, it would set the view by inflating an XML layout file. Because the view holder is not yet assigned to any particular data, the method does not actually set the view's contents.
The layout manager then binds the view holder to its data. It does this by calling the adapter's onBindViewHolder()method, and passing the view holder's position in the RecyclerView. The onBindViewHolder() method needs to fetch the appropriate data, and use it to fill in the view holder's layout. For example, if the RecyclerView is displaying a list of names, the method might find the appropriate name in the list, and fill in the view holder's TextView widget.
If the list needs an update, call a notification method on the RecyclerView.Adapter object, such asnotifyItemChanged(). The layout manager then rebinds any affected view holders, allowing their data to be updated.
layoutManager 調(diào)用adapter的onCreateViewHolder()方法备畦,onCreateViewHolder()方法創(chuàng)建ViewHolder,并設(shè)置view去顯示內(nèi)容许昨。
ViewHolder必須是Adapter類的泛型類型懂盐。一般來說,他需要通過inflating一個(gè)xml布局文件來設(shè)置view糕档。因?yàn)関iewHolder 還沒分配相應(yīng)的數(shù)據(jù)莉恼,這個(gè)方法實(shí)際上并不設(shè)置view的內(nèi)容。
布局管理器通過調(diào)用adapter的OnBindViewHolder()方法速那,以及viewHolder的position來綁定viewHolder和它的數(shù)據(jù)俐银。onBindViewHolder()方法需要選擇相應(yīng)的數(shù)據(jù)來寫入ViewHolder布局中。例如端仰,使用RecyclerView()方法來顯示名稱列表捶惜,這個(gè)方法會(huì)找到列表中相應(yīng)的名稱,然后寫入TextView控件中荔烧。
如果列表需要更新數(shù)據(jù)吱七,調(diào)用notification方法,例如notifyItemChanged()方法鹤竭。布局管理器會(huì)重新綁定相應(yīng)的數(shù)據(jù)踊餐,讓數(shù)據(jù)可以更新。
Tip: You might find the ListAdapter class useful for determining which items in your list need to be updated when the list changes.
你可能會(huì)發(fā)現(xiàn)ListAdapter類有助于在根系數(shù)據(jù)是確認(rèn)那些數(shù)據(jù)需要被更新臀稚。
Customize your RecyclerView
You can customize the RecyclerView objects to meet your specific needs. The standard classes provide all the functionality that most developers will need; in many cases, the only customization you need to do is design the view for each view holder and write the code to update those views with the appropriate data. However, if your app has specific requirements, you can modify the standard behavior in a number of ways. The following sections describe some of the other common customizations.
你可以自定義RecyclerView類來實(shí)現(xiàn)你的特殊需求吝岭。標(biāo)準(zhǔn)類提供來了幾乎所有開發(fā)者需要使用到的方法;在很多情況下吧寺,你只需要去設(shè)計(jì)每個(gè)viewHolder的view窜管,然后通過代碼吧相應(yīng)的數(shù)據(jù)更新到哪些view上。同時(shí)稚机,如果你的app有特殊的需求微峰,你可以修改某些方法的行為。下面的選項(xiàng)描述一些其他的常用定制抒钱。
Modifying the layout
The RecyclerView uses a layout manager to position the individual items on the screen and determine when to reuse item views that are no longer visible to the user. To reuse (or recycle) a view, a layout manager may ask the adapter to replace the contents of the view with a different element from the dataset. Recycling views in this manner improves performance by avoiding the creation of unnecessary views or performing expensive findViewById()lookups. The Android Support Library includes three standard layout managers, each of which offers many customization options:
? LinearLayoutManager arranges the items in a one-dimensional list. Using a RecyclerView with LinearLayoutManager provides functionality like the older ListView layout.
? GridLayoutManager arranges the items in a two-dimensional grid, like the squares on a checkerboard. Using a RecyclerView with GridLayoutManager provides functionality like the older GridView layout.
? StaggeredGridLayoutManager arranges the items in a two-dimensional grid, with each column slightly offset from the one before, like the stars in an American flag.
If none of these layout managers suits your needs, you can create your own by extending the RecyclerView.LayoutManager abstract class.
RecyclerView 使用布局管理器來為那些顯示在屏幕上的item view定位蜓肆,并且決定什么時(shí)候重用那些已經(jīng)不顯示的item view。要重用view谋币,布局管理器可能會(huì)要求適配器使用數(shù)據(jù)集中的不同元素替代視圖中的內(nèi)容仗扬。以這種方式回收view可以避免創(chuàng)建不必要的view,或者是使用代價(jià)昂貴的findViewById()方法蕾额。Android 依賴庫導(dǎo)入了三種標(biāo)準(zhǔn)的布局管理器早芭,每一個(gè)都會(huì)提供很多個(gè)性化的選項(xiàng):
LinearLayoutManager 將item整理為一個(gè)線性布局。使用LinearLayoutManager提供了類似于舊的ListView的功能诅蝶。
GridLayoutManager 將item整理為表格布局退个,就像棋盤上面的方塊募壕。使用GirdLayoutManager提供了類似于舊的GirdView布局的功能。
StaggeredGirdLayoutManager 將item整理為表格布局语盈,每一列都略微偏離舱馅,就像美國國旗上的星星一樣。
如果沒有一個(gè)布局管理器能滿足你的需求刀荒,你可以創(chuàng)建自己的布局管理器代嗤,只要繼承RecyclerView.LayoutManager 抽象類。
Add item animations
Whenever an item changes, the RecyclerView uses an animator to change its appearance. This animator is an object that extends the abstract RecyclerView.ItemAnimator class. By default, the RecyclerView uses DefaultItemAnimator to provide the animation. If you want to provide custom animations, you can define your own animator object by extending RecyclerView.ItemAnimator.
當(dāng)item發(fā)生變化時(shí)缠借,RecyclerView使用動(dòng)畫來改變它們的位置干毅。這個(gè)動(dòng)畫時(shí)抽象類RecyclerView.ItemAnimator的子類。默認(rèn)的泼返,RecyclerView使用DefaultItemAnimator來提供動(dòng)畫效果.如果你想提供自定義動(dòng)畫效果硝逢,你可以實(shí)現(xiàn)RecyclerView.ItemAnimator.
Enable list-item selection
The recyclerview-selection library enables users to select items in RecyclerView list using touch or mouse input. You retain control over the visual presentation of a selected item. You can also retain control over policies controlling selection behavior, such as items that can be eligible for selection, and how many items can be selected.
To add selection support to a RecyclerView instance, follow these steps:
1. Determine which selection key type to use, then build a ItemKeyProvider.There are three key types that you can use to identify selected items: Parcelable (and all subclasses likeUri), String, and Long. For detailed information about selection-key types, seeSelectionTracker.Builder.
2. Implement ItemDetailsLookup.
ItemDetailsLookup enables the selection library to access information about RecyclerView items given aMotionEvent. It is effectively a factory for ItemDetails instances that are backed up by (or extracted from) a RecyclerView.ViewHolder instance.
3. Update item Views in RecyclerView to reflect that the user has selected or unselected it.The selection library does not provide a default visual decoration for the selected items. You must provide this when you implement onBindViewHolder(). The recommended approach is as follows:
? In onBindViewHolder(), call setActivated() (not setSelected()) on the View object with trueor false (depending on if the item is selected).
? Update the styling of the view to represent the activated status. We recommend you use a color state list resource to configure the styling.
4. Use ActionMode to provide the user with tools to perform an action on the selection.
Register a SelectionTracker.SelectionObserver to be notified when selection changes. When a selection is first created, start ActionMode to represent this to the user, and provide selection-specific actions. For example, you may add a delete button to the ActionMode bar, and connect the back arrow on the bar to clear the selection. When the selection becomes empty (if the user cleared the selection the last time), don't forget to terminate action mode.
5. Perform any interpreted secondary actions
At the end of the event processing pipeline, the library may determine that the user is attempting to activate an item by tapping it, or is attempting to drag and drop an item or set of selected items. React to these interpretations by registering the appropriate listener. For more information, see SelectionTracker.Builder.
RecyclerView-selection庫允許用戶點(diǎn)擊并拖動(dòng)RecyclerView的item。你可以控制選中選項(xiàng)的視覺呈現(xiàn)效果绅喉。你也可以對(duì)控制行為的策略進(jìn)行控制趴捅,比如可選項(xiàng)目,或者可選項(xiàng)目的數(shù)量霹疫。
下面步驟可以添加Selection的支持到RecyclerView實(shí)例:
確定使用哪種selection拱绑,然后建立ItemKeyProvider。有三種關(guān)鍵類型你可以選擇來標(biāo)記選中的item:Parcelable及其子類丽蝎、String類型和Long類型猎拨。更多詳細(xì)的信息關(guān)于Selection-key 的類型可以查看SelectionTracker.Builder
實(shí)現(xiàn)ItemDetailsLookup。
ItemDetailsLookup可以得到RecyclerView items獲取到的事件信息屠阻。它實(shí)際上是一個(gè)ViewHolder實(shí)例的備份红省。
- 更新item的事圖來響應(yīng)用戶的選擇或者取消選擇。Selection依賴并沒有提供默認(rèn)的選擇效果国觉,你必須在OnBindViewHolder中提供:
在onBindViewHolder()中吧恃,通過item是否被選中來調(diào)用setActivated()(不是setSelected())方法
更新view的狀態(tài)來顯示活躍狀態(tài)。建議使用 color state list資源來表示是否選中麻诀。
4.通過ActionMode來確定用戶的手勢(shì)操作
注冊(cè)一個(gè)SelectionTracker.SelectionObserver來接收通知狀態(tài)改變的通知痕寓。首次創(chuàng)建section時(shí),啟動(dòng)ActionMode來將其展示給用戶蝇闭,并提供Selection-specific 操作呻率,例如,你可以在ActionMode上添加一個(gè)刪除按鈕呻引,并連接欄上的返回按鈕來清楚操作礼仗。當(dāng)Selection為空時(shí),不要忘記退出操作模式
5.執(zhí)行所有的
在事件處理的最后,庫會(huì)監(jiān)聽到用戶是在嘗試去活躍元践,還是在拖動(dòng)或者丟棄它韭脊。要實(shí)現(xiàn)這樣的效果,需要注冊(cè)一個(gè)相應(yīng)的listener单旁,想要了解更多的信息沪羔,可以查看 SelectionTracker.Builder.
- Assemble everything with SelectionTracker.Builder
The following example shows how to put these pieces together by using the Long selection key:
6.集合所有的東西到 SelectionTracker.Builder
下面的代碼演示了如何使用Long selection key 將這些合到一起:
SelectionTracker tracker = new
SelectionTracker.Builder<>(
"my-selection-id",
recyclerView,
new StableIdKeyProvider(recyclerView),
new MyDetailsLookup(recyclerView),
StorageStrategy.createLongStorage())
.withOnItemActivatedListener(myItemActivatedListener)
.build();
In order to build a SelectionTracker instance, your app must supply the same RecyclerView.Adapterthat you used to initialize RecyclerView to SelectionTracker.Builder. For this reason, you will most likely need to inject the SelectionTracker instance, once created, into your RecyclerView.Adapter after the RecyclerView.Adapter is created. Otherwise, you won't be able to check an item's selected status from the onBindViewHolder() method.
為了創(chuàng)建SelectionTracker實(shí)例,你的APP必須提供初始化RecyclerView的adapter給SelectionTracker.Buillder.因此慎恒,你很可能在adapter創(chuàng)建后將SelectionTracker實(shí)例注入到你的adapter中任内。否則你將無法在OnBindViewHolder()中獲取目標(biāo)的選中狀態(tài).
7. Include selection in the activity lifecycle events.
In order to preserve selection state across the activity lifecycle events, your app must call the selection tracker's onSaveInstanceState() and onRestoreInstanceState() methods from the activity'sonSaveInstanceState() and onRestoreInstanceState() methods respectively. Your app must also supply a unique selection ID to the SelectionTracker.Builder constructor. This ID is required because an activity or a fragment may have more than one distinct, selectable list, all of which need to be persisted in their saved state.
7.在activity的生命周期中使用selection
為了在activity的生命周期中保留選中狀態(tài)撵渡,你的app必須分別在activity的onSaveInstanceState()方法和onREstoreInstanceState()方法中調(diào)用selectiontracker的onSaveInstanceState()方法和onREstoreInstanceState()方法融柬。同時(shí)還要提供特定的Selection ID給SelectionTracker.Builder構(gòu)造器.這個(gè)id是必須的,因?yàn)閍ctivity存在很多不同的可選列表趋距,需要通過它來保留狀態(tài)粒氧。