原文首發(fā) http://blog.lll0.net/post/recyclerview.html
強(qiáng)大而高效的
RecyclerView
ListView
作為一個(gè)強(qiáng)大而有使用頻繁的控件槐沼,但是隨著我們業(yè)務(wù)的發(fā)展慢慢的就感覺 ListView
在某些業(yè)務(wù)場(chǎng)景中已經(jīng)不能滿足我們的業(yè)務(wù)需求曙蒸。舉個(gè)栗子:如果我們?cè)谝粋€(gè)頁面上需要加載不同的布局,在列表中間某一行加載一個(gè)廣告試圖岗钩,而這個(gè)廣告的布局和整個(gè)個(gè)列表的布局樣式是完全不一樣的纽窟。如果放在ListView
中,這種布局是不太好實(shí)現(xiàn)的兼吓。但是放在Google 提出的新控件 ReyclerView 中 實(shí)現(xiàn)這種布局是非常簡(jiǎn)單的臂港。
RecyclerView 是Android L版本中新添加的一個(gè)用來取代ListView的SDK,它的靈活性與可替代性比listview更好。
基本介紹
在使用RecyclerView中引入了幾個(gè)相關(guān)的類
-
LayoutManager
用來確定每一個(gè)item如何進(jìn)行排列擺放趋艘,何時(shí)展示和隱藏疲恢。回收或重用一個(gè)View的時(shí)候瓷胧,LayoutManager會(huì)向適配器請(qǐng)求新的數(shù)據(jù)來替換舊的數(shù)據(jù)显拳,這種機(jī)制避免了創(chuàng)建過多的View和頻繁的調(diào)用findViewById方法(與ListView原理類似)。Google 為我們提供了 幾個(gè)基礎(chǔ)的布局- LinearLayoutManager 線性布局布局樣式和ListView一樣 呈現(xiàn)的是線性
- GridLayoutManager 表格布局與GridView 一樣
- StaggeredGridLayoutManager 瀑布流布局 這是新的布局 簡(jiǎn)單描述就是加載的每個(gè)item在頁面上占有的空間都是不一樣的布局
-
RecyclerView.Adapter
RecyclerView 的適配器 數(shù)據(jù)的加載和item 的綁定都是通過這個(gè)類來實(shí)現(xiàn)搓萧。在使用的時(shí)候需要繼承該類來進(jìn)行相應(yīng)的處理 -
RecyclerView.ViewHolder
同樣是使用中需要繼承該類杂数,然后進(jìn)行把數(shù)據(jù)和item里面的布局進(jìn)行綁定
在使用的時(shí)候 其實(shí)不用考慮復(fù)用的問題。
簡(jiǎn)單使用
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.創(chuàng)建布局之后需要在Activity中獲得這個(gè)控件揍移,并聲明LayoutManager
與Adapter
,代碼如下
mRecycler = (RecyclerView) findViewById(R.id.recycler);
mRecycler.setLayoutManager(new LinearLayoutManager(mActitivity));
recyclerViewAdapter = new RecyclerViewAdapter(beans,mActitivity);
mRecycler.setAdapter(recyclerViewAdapter);
4.Adapter的創(chuàng)建
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. 傳入不同的數(shù)據(jù)源反肋,對(duì)應(yīng)的位置加載不同的布局
* 2. 傳入一個(gè)數(shù)據(jù)源那伐,但是通過數(shù)據(jù)源里面特殊的字段判斷加載什么布局
*/
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) {
//通過這個(gè)區(qū)分加載不同 view
//通過判斷特殊的字段加載不同的布局
return bean.get(position).type;
}
@Override
public RecyclerViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
//通過 getTtemViewType 返回的 內(nèi)容加載不同 的布局
//假設(shè)加載 三中布局分別對(duì)應(yīng) 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 為不同的布局綁定對(duì)應(yīng)的數(shù)據(jù)
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() {
//主要是計(jì)算 加載數(shù)據(jù)的總數(shù)
return bean.size();
}
}
5.RecyclerView.ViewHolder 子類的實(shí)現(xiàn) ,這是一個(gè)通用的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對(duì)象
private Context mContext;//上下文對(duì)象
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> 具體的是那個(gè)控件
* @return 當(dāng)然是返回你要找的控件了
*/
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的到用戶的空間對(duì)象
*
* @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;
}
/**
* 通過該方法可以的到對(duì)應(yīng)控件的點(diǎn)擊事件
*
* @param viewId 控件的id
* @param listener 需要實(shí)現(xiàn)的監(jiān)聽器
* @return
*/
public RecyclerViewHolder setClickListener(int viewId, View.OnClickListener listener) {
View view = findViewById(viewId);
view.setOnClickListener(listener);
return this;
}
}
運(yùn)行
只要實(shí)現(xiàn)以上代碼,就能實(shí)現(xiàn)具體的內(nèi)容养距。