RecyclerView是一種新的視圖組,目標是爲任何基於適配器的視圖提供相似的渲染方式。它被作爲ListView和GridView控件的繼承者,在最新的support-V7版本中提供支持。
有了 ListView、GridView 爲什麼還需要 RecyclerView 這樣的控件?
優點 :RecyclerView 提供了一種插拔式的體驗,高度的解耦,異常的靈活,通過設置它提供的不同LayoutManager,ItemDecoration , ItemAnimator 實現 ListView,GridView,瀑布流的效果。
- 你想要控制其顯示的方式,請通過佈局管理器LayoutManager
- 你想要控制 Item 間的間隔(可繪製),請通過 ItemDecoration
- 你想要控制 Item 增刪的動畫,請通過 ItemAnimator
缺點 :缺少 Item 點擊事件,沒有添加頭部 View 基本使用
簡單使用
- 初始化控件 :mRecyclerView = findView(R.id.id_recyclerview);
- 設置佈局管理器:mRecyclerView.setLayoutManager(layout);
- 設 置 adapter:mRecyclerView.setAdapter(adapter)
佈局管理器
RecyclerView.LayoutManager,這是一個抽象類,系統提供了 3 個實現類:
- LinearLayoutManager 現行管理器,支持橫向、縱向。
- GridLayoutManager 網格佈局管理器
- StaggeredGridLayoutManager 瀑布流式佈局管理器
線性佈局
rv.setLayoutManager(new LinearLayoutManager(this,LinearLayoutManager.HORIZONTAL,true));
- 第一個參數是上下文
- 第二個參數是我們的佈局管理器橫向展示還是縱向展示
- 第三個參數是 true 從末尾展示,相反從頭展示
網格佈局
rv.setLayoutManager(new GridLayoutManager(this,3,GridLayoutManager.HORIZONTAL,true));
- 第一個參數是上下文
- 第二個參數相對第三個參數而講 如果是橫向的代表三列 如果是豎直的代表三行
- 第三個參數我們的佈局管理器橫向展示還是縱向展示
- 第四個參數是 true 從末尾展示,相反從頭展示
瀑布流管理器
new StaggeredGridLayoutManager(3,StaggeredGridLayoutManager.VERTICAL)
注意:在使用瀑布流管理器的時候 需要給每個 item 隨機數設置相應高度
我們可以在viewholder 中對 imageview 動態設置高度
RecyclerView.Adapter 適配器
創建適配器類繼承RecycleView的Adapter,步驟爲:
- 繼承RecyclerView.Adapter,並且在Adapter裏面聲明ViewHolder類繼承RecyclerView.ViewHolder,最後把自己的ViewHolder類丟進自己的Adapter類的泛型中去。
- 在自定義ViewHolder類的構造方法中可以通過ID找到佈局的控件,控件需要聲明爲自定義ViewHolder類的成員變量。
- 實現RecyclerView.Adapter的所有未實現的函數,onCreateViewHolder主要負責加載佈局(加載的時候注意要把父佈局寫到參數裏去),創建自定義ViewHolder類的對象;onBindViewHolder主要負責把數據設置到Item的控件中;getItemCount主要負責得到數據的數目。
- 最好把數據聲明爲成員變量,在構造函數裏面傳進來。
- 由於RecycleView原生不支持點擊事件,需要自己添加接口進行回調。
瀑布流佈局實例
ps:其他佈局我已經再其他案例中應用過,瀑布流這種佈局目前沒有練習。
案例只要通過本地圖片加載顯示,不用考慮內存機制,圖片加載框架。
效果圖如下:
子佈局
<?xml version="1.0" encoding="utf-8"?>
<androidx.cardview.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:card_view="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="1dp"
card_view:cardBackgroundColor="@color/white"
card_view:cardCornerRadius="8dp"
android:elevation="8dp"
>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
>
<ImageView
android:id="@+id/masonry_item_img"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:adjustViewBounds="true"
android:scaleType="centerCrop" />
<TextView
android:id="@+id/masonry_item_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
/>
</LinearLayout>
</androidx.cardview.widget.CardView>
MainActivity.java
public class MainActivity extends AppCompatActivity {
private RecyclerView recyclerView;
private List<Product> productList=new ArrayList<Product>();
private Product mProduct;
// 展示的文字
private String[] texts = new String[] {
"已知花意,未見其花。已見其花,未聞花名。", "此生無悔入四月,來世願做友人。",
"此生無悔入夏目,來世願做帳中妖。", "安茲王屠帝,號天下於此。",
"如果幸福有顏色的話,那一定的被末日所染紅的藍色", "吾王劍之所指,吾等心之所向。",
"無論在什麼地方,什麼時候,在我們的頭頂都是同樣悠遠的天穹,就好像是永遠都無法分開的羈絆","鏡子裏顯示出來的永遠只是真實的影像,而不是真實的自己。",
"人類的心裏住着一隻野獸,純粹,兇猛,無法馴養,那是一隻叫做“嫉妒”的野獸" ,"如果我閉上了雙眼,看到的是黑暗的話,那麼當我睜開眼睛去看這個世界的時候,是否會是一片光明?",
"我想成爲一個溫柔的人,因爲曾被溫柔的人那樣對待,深深瞭解那種被溫柔相待的感覺。","如果時光可以倒流 我還是會選擇認識你 雖然會傷痕累累 但是心中的溫暖記憶是誰都無法給與的 謝謝你來過我的世界",
"無論在哪裏遇到你,我都會喜歡上你","只要有你在,我就無所不能。",
};
private int[] photo = new int[] { R.mipmap.t1,R.mipmap.t2,R.mipmap.t3,R.mipmap.t4,R.mipmap.t5,R.mipmap.t6,R.mipmap.t7,R.mipmap.t8,R.mipmap.t9,
R.mipmap.t10,R.mipmap.t11,R.mipmap.t12,R.mipmap.t13,R.mipmap.t14};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
recyclerView= (RecyclerView) findViewById(R.id.recycler);
//設置layoutManager
recyclerView.setLayoutManager(new StaggeredGridLayoutManager(2,StaggeredGridLayoutManager.VERTICAL));
//設置adapter
initData();
MasonryAdapter adapter=new MasonryAdapter(productList);
recyclerView.setAdapter(adapter);
//設置item之間的間隔
SpacesItemDecoration decoration=new SpacesItemDecoration(16);
recyclerView.addItemDecoration(decoration);
}
private void initData() {
for (int i=0;i<texts.length;i++){
mProduct=new Product(photo[i],texts[i]);
productList.add(mProduct);
}
}
public class SpacesItemDecoration extends RecyclerView.ItemDecoration {
private int space;
public SpacesItemDecoration(int space) {
this.space=space;
}
@Override
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
outRect.left=space;
outRect.right=space;
outRect.bottom=space;
if(parent.getChildAdapterPosition(view)==0){
outRect.top=space;
}
}
}
}
適配器
public class MasonryAdapter extends RecyclerView.Adapter<MasonryAdapter.MasonryView> {
private List<Product> products;
public MasonryAdapter(List<Product> list) {
products = list;
}
@Override
public MasonryView onCreateViewHolder(ViewGroup viewGroup, int i) {
View view = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.masonry_item, viewGroup, false);
return new MasonryView(view);
}
@Override
public void onBindViewHolder(MasonryView masonryView, int position) {
masonryView.imageView.setImageResource(products.get(position).getImg());
masonryView.textView.setText(products.get(position).getTitle());
}
@Override
public int getItemCount() {
return products.size();
}
public static class MasonryView extends RecyclerView.ViewHolder {
ImageView imageView;
TextView textView;
public MasonryView(View itemView) {
super(itemView);
imageView = (ImageView) itemView.findViewById(R.id.masonry_item_img);
textView = (TextView) itemView.findViewById(R.id.masonry_item_title);
}
}
}