原文首發 http://blog.lll0.net/post/recyclerview.html
強大而高效的
RecyclerView
ListView
作為一個強大而有使用頻繁的控件,但是隨著我們業務的發展慢慢的就感覺 ListView
在某些業務場景中已經不能滿足我們的業務需求。舉個栗子:如果我們在一個頁面上需要加載不同的布局,在列表中間某一行加載一個廣告試圖,而這個廣告的布局和整個個列表的布局樣式是完全不一樣的。如果放在ListView
中,這種布局是不太好實現的。但是放在Google 提出的新控件 ReyclerView 中 實現這種布局是非常簡單的。
RecyclerView 是Android L版本中新添加的一個用來取代ListView的SDK,它的靈活性與可替代性比listview更好。
基本介紹
在使用RecyclerView中引入了幾個相關的類
-
LayoutManager
用來確定每一個item如何進行排列擺放,何時展示和隱藏。回收或重用一個View的時候,LayoutManager會向適配器請求新的數據來替換舊的數據,這種機制避免了創建過多的View和頻繁的調用findViewById方法(與ListView原理類似)。Google 為我們提供了 幾個基礎的布局- LinearLayoutManager 線性布局布局樣式和ListView一樣 呈現的是線性
- GridLayoutManager 表格布局與GridView 一樣
- StaggeredGridLayoutManager 瀑布流布局 這是新的布局 簡單描述就是加載的每個item在頁面上占有的空間都是不一樣的布局
-
RecyclerView.Adapter
RecyclerView 的適配器 數據的加載和item 的綁定都是通過這個類來實現。在使用的時候需要繼承該類來進行相應的處理 -
RecyclerView.ViewHolder
同樣是使用中需要繼承該類,然后進行把數據和item里面的布局進行綁定
在使用的時候 其實不用考慮復用的問題。
簡單使用
1.添加依賴在build.gradle
中添加依賴 ,然后同步一下 引入依賴需要的包
dependencies {
compile 'com.android.support:recyclerview-v7:25.1.1'
}
2.布局中使用RecylerView
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="net.lll0.bus.ui.test_activity.RecyclerViewTestActivity">
<android.support.v7.widget.RecyclerView
android:id="@+id/recycler"
android:layout_width="368dp"
android:layout_height="551dp"
app:layout_constraintBottom_toBottomOf="parent"
android:layout_marginBottom="8dp"
android:layout_marginLeft="8dp"
app:layout_constraintLeft_toLeftOf="parent"
android:layout_marginRight="8dp"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:layout_marginTop="8dp" />
</android.support.constraint.ConstraintLayout>
3.創建布局之后需要在Activity中獲得這個控件,并聲明LayoutManager
與Adapter
,代碼如下
mRecycler = (RecyclerView) findViewById(R.id.recycler);
mRecycler.setLayoutManager(new LinearLayoutManager(mActitivity));
recyclerViewAdapter = new RecyclerViewAdapter(beans,mActitivity);
mRecycler.setAdapter(recyclerViewAdapter);
4.Adapter的創建
package net.lll0.bus.adapter.test;
import android.content.Context;
import android.support.v7.widget.RecyclerView;
import android.text.Layout;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import net.lll0.bus.suzhoubus.R;
import net.lll0.bus.adapter.RecyclerViewHolder;
import java.util.List;
/**
* Created by liang on 2017/8/24.
*/
public class RecyclerViewAdapter extends RecyclerView.Adapter<RecyclerViewHolder> {
private String typeView01 = "item1";
private String typeView02 = "item2";
/**
* 加載不同的兩種方式
* 1. 傳入不同的數據源,對應的位置加載不同的布局
* 2. 傳入一個數據源,但是通過數據源里面特殊的字段判斷加載什么布局
*/
private List<Bean> bean;
private Context mContext;
public RecyclerViewAdapter(List<Bean> bean, Context mContext) {
this.bean = bean;
this.mContext = mContext;
}
@Override
public int getItemViewType(int position) {
//通過這個區分加載不同 view
//通過判斷特殊的字段加載不同的布局
return bean.get(position).type;
}
@Override
public RecyclerViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
//通過 getTtemViewType 返回的 內容加載不同 的布局
//假設加載 三中布局分別對應 1 2 3
if (1 == viewType) {
return new RecyclerViewHolder(mContext,LayoutInflater.from(mContext).inflate(R.layout.item, parent, false), viewType);
} else if (2 == viewType) {
return new RecyclerViewHolder(mContext,LayoutInflater.from(mContext).inflate(R.layout.item_lineinfo, parent, false), viewType);
} else if (3 == viewType) {
return new RecyclerViewHolder(mContext,LayoutInflater.from(mContext).inflate(R.layout.nav_header_home, parent, false), viewType);
}
return null;
}
@Override
public void onBindViewHolder(RecyclerViewHolder holder, int position) {
//onCreateViewHolder 為不同的布局綁定對應的數據
Bean bean = this.bean.get(position);
int type = bean.type;
if (1 == type) {
holder.setText(R.id.textView2,"textView2");
holder.setText(R.id.textView3,"textView3");
} else if (2 == type) {
holder.setText(R.id.lineinfo_index,position+"");
} else if (3 == type) {
}
}
@Override
public int getItemCount() {
//主要是計算 加載數據的總數
return bean.size();
}
}
5.RecyclerView.ViewHolder 子類的實現 ,這是一個通用的ViewHolder
package net.lll0.bus.adapter;
import android.content.Context;
import android.support.v7.widget.RecyclerView;
import android.util.SparseArray;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.TextView;
/**
* Created by liang on 2016/2/15.
*/
public class RecyclerViewHolder extends RecyclerView.ViewHolder {
private SparseArray<View> mViews;//集合類,layout里包含的View,以view的id作為key,value是view對象
private Context mContext;//上下文對象
private int type;
public RecyclerViewHolder(Context ctx, View itemView) {
super(itemView);
mContext = ctx;
mViews = new SparseArray<View>();
}
public RecyclerViewHolder(Context ctx, View itemView,int type) {
super(itemView);
mContext = ctx;
mViews = new SparseArray<View>();
this.type = type;
}
public View getItemView() {
return itemView;
}
/*
* 通過空間id在SparseArray集合中找出用戶View
* @param viewId 控件的id
* @param <T> 具體的是那個控件
* @return 當然是返回你要找的控件了
*/
private <T extends View> T findViewById(int viewId) {
View view = mViews.get(viewId);
if (view == null) {
view = itemView.findViewById(viewId);
mViews.put(viewId, view);
}
return (T) view;
}
/**
* 通過findViewById以及控件id的到用戶的空間對象
*
* @param viewId
* @return
*/
public View getView(int viewId) {
return findViewById(viewId);
}
public TextView getTextView(int viewId) {
return (TextView) getView(viewId);
}
public Button getButton(int viewId) {
return (Button) getView(viewId);
}
public ImageView getImageView(int viewId) {
return (ImageView) getView(viewId);
}
public ImageButton getImageButton(int viewId) {
return (ImageButton) getView(viewId);
}
public EditText getEditText(int viewId) {
return (EditText) getView(viewId);
}
public RecyclerViewHolder setText(int viewId, String value) {
TextView view = findViewById(viewId);
view.setText(value);
return this;
}
public RecyclerViewHolder setBackground(int viewId, int resId) {
View view = findViewById(viewId);
view.setBackgroundResource(resId);
return this;
}
public int getType() {
return type;
}
public void setType(int type) {
this.type = type;
}
/**
* 通過該方法可以的到對應控件的點擊事件
*
* @param viewId 控件的id
* @param listener 需要實現的監聽器
* @return
*/
public RecyclerViewHolder setClickListener(int viewId, View.OnClickListener listener) {
View view = findViewById(viewId);
view.setOnClickListener(listener);
return this;
}
}
運行
只要實現以上代碼,就能實現具體的內容。