項目中,咱們用得最多的元素就是列表了,在Android 中,實現列表用原生的RecyclerView就能知足需求,關於RecyclerView 的基礎使用這裏不作過多的介紹,網上有太多的博文介紹了。本篇文章將介紹本身封裝的一個Adapter,幫你快速高效的添加一個列表(包括單 Item 列表和多item列表)。java
1, 構造一個通用的Adapter模版,避免每添加一個列表就要寫一個Adapter,避免寫Adapter中的大量重複代碼。
2,經過組裝的方式來構建Adapter,將每一種(ViewType不一樣的)Item抽象成一個單獨組件,Adapter 就是一個殼,咱們只須要向Adapter中添加Item就行,這樣作的好處就是減小耦合,去掉一種item 或者添加一種item對於列表是沒有任何影響的。
3,高內聚,低耦合,擴展方便。git
爲每一種 viewType 定義一個Cell,Cell就是上面提到的獨立組件,它負責建立ViewHolder,數據綁定和邏輯處理。它有2個重要的方法,onCreateViewHolder 負責建立ViewHolder,onBindViewHolder負責數據綁定,這兩個方法的定義和生命週期同Adapter種的2個方法同樣,事實上,Adapter 中的onCreateViewHolder和onBindViewHolder 最終調用的是Cell中的方法。github
一種 ViewType 對應一個Cell
看一個示例:服務器
如上圖:以豆瓣APP的首頁爲例,文章包含圖片和視頻的兩個Item 的佈局是不一樣的,所以,能夠添加兩個Cell(ImageCell和VideoCell)來分別處理這兩種Item。 網絡
有了Cell以後,要向列表添加添加Header和Footer 的需求就很簡單了,咱們直接添加一個HeaderCell和FooterCell 就能夠了,也不用更改Adapter代碼,是否是很方便。此外,還能夠用Cell實現列表LoadMore(加載更多)狀態、Loadding(加載中)狀態、Empty(空頁面)狀態、Error(出錯)狀態 View的顯示。ide
介紹:1,base:base包下面爲Lib的主要代碼,一個Cell接口和三個抽象類,分別抽取了Adapter,ViewHolder,Cell的公共邏輯。
2,cell:cell包下面有4個cell,分別顯示列表的LoadMore,Loading,Empty,Error狀態。
3,fragment:有一個Fragment抽象類,定義了一個UI模版(不須要額外添加布局文件),要實現列表的界面只須要繼承AbsBaseFragment,實現幾個方法添加數據就OK。佈局
/** * Created by zhouwei on 17/1/19. */
public interface Cell {
/** * 回收資源 * */
public void releaseResource();
/** * 獲取viewType * @return */
public int getItemType();
/** * 建立ViewHolder * @param parent * @param viewType * @return */
public RVBaseViewHolder onCreateViewHolder(ViewGroup parent, int viewType);
/** * 數據綁定 * @param holder * @param position */
public void onBindViewHolder(RVBaseViewHolder holder, int position);
}複製代碼
定義了4個方法,除了回收資源的方法releaseResource(),其它三個和Adapter中的同樣。post
/** * Created by zhouwei on 17/1/19. */
public abstract class RVBaseCell<T> implements Cell {
public RVBaseCell(T t){
mData = t;
}
public T mData;
@Override
public void releaseResource() {
// do nothing
// 若是有須要回收的資源,子類本身實現
}
}複製代碼
抽象類,接受一個範型T(Cell接受的數據實體),實現了releaseResource方法,但什麼事也沒幹,由於有不少簡單的Cell沒有資源回收,就不須要實現。若是子類Cell 有資源回收,重寫這個方法就能夠了。this
/** * Created by zhouwei on 17/1/19. */
public class RVBaseViewHolder extends RecyclerView.ViewHolder{
private SparseArray<View> views;
private View mItemView;
public RVBaseViewHolder(View itemView) {
super(itemView);
views = new SparseArray<>();
mItemView = itemView;
}
/** * 獲取ItemView * @return */
public View getItemView() {
return mItemView;
}
public View getView(int resId) {
return retrieveView(resId);
}
public TextView getTextView(int resId){
return retrieveView(resId);
}
public ImageView getImageView(int resId){
return retrieveView(resId);
}
public Button getButton(int resId){
return retrieveView(resId);
}
@SuppressWarnings("unchecked")
protected <V extends View> V retrieveView(int viewId){
View view = views.get(viewId);
if(view == null){
view = mItemView.findViewById(viewId);
views.put(viewId,view);
}
return (V) view;
}
public void setText(int resId,CharSequence text){
getTextView(resId).setText(text);
}
public void setText(int resId,int strId){
getTextView(resId).setText(strId);
}
}複製代碼
之前寫Adapter的時候,每一種viewType 都對應了一個ViewHolder,其中有大量的findViewById綁定視圖,有了RVBaseViewHolder,不再須要定義ViewHolder了,經過id獲取View就行,View用SparseArray 保存進行了複用,避免每一次都find。spa
/** * Created by zhouwei on 17/1/19. */
public abstract class RVBaseAdapter<C extends RVBaseCell> extends RecyclerView.Adapter<RVBaseViewHolder>{
public static final String TAG = "RVBaseAdapter";
protected List<C> mData;
public RVBaseAdapter(){
mData = new ArrayList<>();
}
public void setData(List<C> data) {
addAll(data);
notifyDataSetChanged();
}
public List<C> getData() {
return mData;
}
@Override
public RVBaseViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
for(int i=0;i<getItemCount();i++){
if(viewType == mData.get(i).getItemType()){
return mData.get(i).onCreateViewHolder(parent,viewType);
}
}
throw new RuntimeException("wrong viewType");
}
@Override
public void onBindViewHolder(RVBaseViewHolder holder, int position) {
mData.get(position).onBindViewHolder(holder,position);
}
@Override
public void onViewDetachedFromWindow(RVBaseViewHolder holder) {
super.onViewDetachedFromWindow(holder);
Log.e(TAG,"onViewDetachedFromWindow invoke...");
//釋放資源
int position = holder.getAdapterPosition();
//越界檢查
if(position<0 || position>=mData.size()){
return;
}
mData.get(position).releaseResource();
}
@Override
public int getItemCount() {
return mData == null ? 0:mData.size();
}
@Override
public int getItemViewType(int position) {
return mData.get(position).getItemType();
}
/** * add one cell * @param cell */
public void add(C cell){
mData.add(cell);
int index = mData.indexOf(cell);
notifyItemChanged(index);
}
public void add(int index,C cell){
mData.add(index,cell);
notifyItemChanged(index);
}
/** * remove a cell * @param cell */
public void remove(C cell){
int indexOfCell = mData.indexOf(cell);
remove(indexOfCell);
}
public void remove(int index){
mData.remove(index);
notifyItemRemoved(index);
}
/** * * @param start * @param count */
public void remove(int start,int count){
if((start +count) > mData.size()){
return;
}
int size = getItemCount();
for(int i =start;i<size;i++){
mData.remove(i);
}
notifyItemRangeRemoved(start,count);
}
/** * add a cell list * @param cells */
public void addAll(List<C> cells){
if(cells == null || cells.size() == 0){
return;
}
Log.e("zhouwei","addAll cell size:"+cells.size());
mData.addAll(cells);
notifyItemRangeChanged(mData.size()-cells.size(),mData.size());
}
public void addAll(int index,List<C> cells){
if(cells == null || cells.size() == 0){
return;
}
mData.addAll(index,cells);
notifyItemRangeChanged(index,index+cells.size());
}
public void clear(){
mData.clear();
notifyDataSetChanged();
}
/** * 若是子類須要在onBindViewHolder 回調的時候作的操做能夠在這個方法裏作 * @param holder * @param position */
protected abstract void onViewHolderBound(RVBaseViewHolder holder, int position);
}複製代碼
RVBaseAdapter 繼承 RecyclerView.Adapter,接受的是RVBaseCell類型,保存了一個Cell 列表。其中還有有添加、移除,清空、更新數據的方法。
注意其中幾個方法:
1,getItemViewType: 調用的是對應position Cell 的getItemViewType 方法。
2,onCreateViewHolder:調用Cell 的onCreateViewHolder 建立ViewHolder。
3,onBindViewHolder: 調用對應Cell的onBindViewHolder 方法綁定數據
4,onViewDetachedFromWindow: 資源回收
/** * Created by zhouwei on 17/1/23. */
public class RVSimpleAdapter extends RVBaseAdapter{
public static final int ERROR_TYPE = Integer.MAX_VALUE -1;
public static final int EMPTY_TYPE = Integer.MAX_VALUE -2;
public static final int LOADING_TYPE = Integer.MAX_VALUE -3;
public static final int LOAD_MORE_TYPE = Integer.MAX_VALUE -4;
private EmptyCell mEmptyCell;
private ErrorCell mErrorCell;
private LoadingCell mLoadingCell;
private LoadMoreCell mLoadMoreCell;
//LoadMore 是否已顯示
private boolean mIsShowLoadMore = false;
public RVSimpleAdapter(){
mEmptyCell = new EmptyCell(null);
mErrorCell = new ErrorCell(null);
mLoadingCell = new LoadingCell(null);
mLoadMoreCell = new LoadMoreCell(null);
}
@Override
protected void onViewHolderBound(RVBaseViewHolder holder, int position) {
}
@Override
public void onAttachedToRecyclerView(RecyclerView recyclerView) {
super.onAttachedToRecyclerView(recyclerView);
RecyclerView.LayoutManager manager = recyclerView.getLayoutManager();
//處理GridView 佈局
if(manager instanceof GridLayoutManager){
final GridLayoutManager gridLayoutManager = (GridLayoutManager) manager;
gridLayoutManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {
@Override
public int getSpanSize(int position) {
int viewType = getItemViewType(position);
return (viewType == ERROR_TYPE|| viewType == EMPTY_TYPE || viewType == LOADING_TYPE
||viewType == LOAD_MORE_TYPE) ? gridLayoutManager.getSpanCount():1;
}
});
}
}
@Override
public void onViewAttachedToWindow(RecyclerView.ViewHolder holder) {
// 處理StaggeredGridLayoutManager 顯示這個Span
int position = holder.getAdapterPosition();
int viewType = getItemViewType(position);
if(isStaggeredGridLayout(holder)){
if(viewType == ERROR_TYPE|| viewType == EMPTY_TYPE || viewType == LOADING_TYPE
||viewType == LOAD_MORE_TYPE){
StaggeredGridLayoutManager.LayoutParams params = (StaggeredGridLayoutManager.LayoutParams) holder.itemView.getLayoutParams();
//設置顯示整個span
params.setFullSpan(true);
}
}
}
private boolean isStaggeredGridLayout(RecyclerView.ViewHolder holder) {
ViewGroup.LayoutParams layoutParams = holder.itemView.getLayoutParams();
if (layoutParams != null && layoutParams instanceof StaggeredGridLayoutManager.LayoutParams) {
return true;
}
return false;
}
/** * 顯示LoadingView * <p>請求數據時調用,數據請求完畢時調用{@link #hideLoading }</p> * @see #showLoadingKeepCount(int) */
public void showLoading(){
clear();
add(mLoadingCell);
}
public void showLoading(View loadingView){
if(loadingView == null){
showLoading();
}
clear();
mLoadingCell.setLoadingView(loadingView);
add(mLoadingCell);
}
/** * 顯示LoadingView * <p>列表顯示LoadingView並保留keepCount個Item</p> * @param keepCount 保留的條目數量 */
public void showLoadingKeepCount(int keepCount){
if(keepCount < 0 || keepCount>mData.size()){
return;
}
remove(keepCount,mData.size() - keepCount);
if(mData.contains(mLoadingCell)){
mData.remove(mLoadingCell);
}
add(mLoadingCell);
}
/** * hide Loading view */
public void hideLoading(){
if(mData.contains(mLoadingCell)){
mData.remove(mLoadingCell);
}
}
/** * 顯示錯誤提示 * <p>當網絡請求發生錯誤,須要在界面給出錯誤提示時,調用{@link #showError}</p> * @see #showErrorKeepCount(int) */
public void showError(){
clear();
add(mErrorCell);
}
/** * 顯示錯誤提示 * <p>當網絡請求發生錯誤,須要在界面給出錯誤提示時,調用{@link #showErrorKeepCount(int)},並保留keepCount 條Item</p> * @param keepCount 保留Item數量 */
public void showErrorKeepCount(int keepCount){
if(keepCount < 0 || keepCount>mData.size()){
return;
}
remove(keepCount,mData.size() - keepCount);
if(mData.contains(mErrorCell)){
mData.remove(mErrorCell);
}
add(mErrorCell);
}
/** * 隱藏錯誤提示 */
public void hideErorr(){
if(mData.contains(mErrorCell)){
remove(mErrorCell);
}
}
/** * 顯示LoadMoreView * <p>當列表滑動到底部時,調用{@link #showLoadMore()} 提示加載更多,加載完數據,調用{@link #hideLoadMore()} * 隱藏LoadMoreView,顯示列表數據。</p> * */
public void showLoadMore(){
if(mData.contains(mLoadMoreCell)){
return;
}
add(mLoadMoreCell);
mIsShowLoadMore = true;
}
/** * 隱藏LoadMoreView * <p>調用{@link #showLoadMore()}以後,加載數據完成,調用{@link #hideLoadMore()}隱藏LoadMoreView</p> */
public void hideLoadMore(){
if(mData.contains(mLoadMoreCell)){
remove(mLoadMoreCell);
mIsShowLoadMore = false;
}
}
/** * LoadMore View 是否已經顯示 * @return */
public boolean isShowLoadMore() {
return mIsShowLoadMore;
}
/** * * @param keepCount */
public void showEmptyKeepCount(int keepCount){
if(keepCount < 0 || keepCount>mData.size()){
return;
}
remove(keepCount,mData.size() - keepCount);
if(mData.contains(mEmptyCell)){
mData.remove(mEmptyCell);
}
add(mEmptyCell);
}
/** * 顯示空view * <p>當頁面沒有數據的時候,調用{@link #showEmpty()}顯示空View,給用戶提示</p> */
public void showEmpty(){
clear();
add(mEmptyCell);
}
/** * 隱藏空View */
public void hideEmpty(){
if(mData.contains(mEmptyCell)){
remove(mEmptyCell);
}
}
}複製代碼
RVSimpleAdapter 是RVBaseAdapter 的默認實現類,添加了顯示LoadMore View、Loading View 、Empty View、ErrorView 的功能。
/** * Created by zhouwei on 17/2/3. */
public abstract class AbsBaseFragment<T> extends Fragment {
protected RecyclerView mRecyclerView;
protected RVSimpleAdapter mBaseAdapter;
private FrameLayout mToolbarContainer;
protected SwipeRefreshLayout mSwipeRefreshLayout;
/** * RecyclerView 最後可見Item在Adapter中的位置 */
private int mLastVisiblePosition = -1;
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.base_fragment_layout,null);
return view;
}
@Override
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
mSwipeRefreshLayout = (SwipeRefreshLayout) view.findViewById(R.id.base_refresh_layout);
mToolbarContainer = (FrameLayout) view.findViewById(R.id.toolbar_container);
mRecyclerView = (RecyclerView) view.findViewById(R.id.base_fragment_rv);
mRecyclerView.setLayoutManager(initLayoutManger());
mBaseAdapter = initAdapter();
mRecyclerView.setAdapter(mBaseAdapter);
mSwipeRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
@Override
public void onRefresh() {
setRefreshing(true);
onPullRefresh();
}
});
mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
@Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
RecyclerView.LayoutManager layoutManager = recyclerView.getLayoutManager();
if(layoutManager instanceof LinearLayoutManager){
mLastVisiblePosition = ((LinearLayoutManager)layoutManager).findLastVisibleItemPosition();
}else if(layoutManager instanceof GridLayoutManager){
mLastVisiblePosition = ((GridLayoutManager)layoutManager).findLastVisibleItemPosition();
}else if(layoutManager instanceof StaggeredGridLayoutManager){
StaggeredGridLayoutManager staggeredGridLayoutManager = (StaggeredGridLayoutManager) layoutManager;
int []lastPositions = new int[staggeredGridLayoutManager.getSpanCount()];
staggeredGridLayoutManager.findLastVisibleItemPositions(lastPositions);
mLastVisiblePosition = findMax(lastPositions);
}
}
@Override
public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
View firstView = recyclerView.getChildAt(0);
int top = firstView.getTop();
int topEdge = recyclerView.getPaddingTop();
//判斷RecyclerView 的ItemView是否滿屏,若是不滿一屏,上拉不會觸發加載更多
boolean isFullScreen = top < topEdge;
RecyclerView.LayoutManager manager = recyclerView.getLayoutManager();
int itemCount = manager.getItemCount();
//由於LoadMore View 是Adapter的一個Item,顯示LoadMore 的時候,Item數量+1了,致使 mLastVisibalePosition == itemCount-1
// 判斷兩次都成立,所以必須加一個判斷條件 !mBaseAdapter.isShowLoadMore()
if(newState == RecyclerView.SCROLL_STATE_IDLE && mLastVisiblePosition == itemCount-1 && isFullScreen && !mBaseAdapter.isShowLoadMore()){
//最後一個Item了
mBaseAdapter.showLoadMore();
onLoadMore();
}
}
});
View toolbarView = addToolbar();
if(toolbarView!=null && mToolbarContainer!=null
){
mToolbarContainer.addView(toolbarView);
}
onRecyclerViewInitialized();
}
/** * hide load more progress */
public void hideLoadMore(){
if(mBaseAdapter!=null){
mBaseAdapter.hideLoadMore();
}
}
/** * 獲取組數最大值 * @param lastPositions * @return */
private int findMax(int[] lastPositions) {
int max = lastPositions[0];
for (int value : lastPositions) {
if (value > max) {
max = value;
}
}
return max;
}
/** * 設置刷新進度條的顏色 * see{@link SwipeRefreshLayout#setColorSchemeResources(int...)} * @param colorResIds */
public void setColorSchemeResources(@ColorRes int... colorResIds){
if(mSwipeRefreshLayout!=null){
mSwipeRefreshLayout.setColorSchemeResources(colorResIds);
}
}
/** * 設置刷新進度條的顏色 * see{@link SwipeRefreshLayout#setColorSchemeColors(int...)} * @param colors */
public void setColorSchemeColors(int... colors){
if(mSwipeRefreshLayout!=null){
mSwipeRefreshLayout.setColorSchemeColors(colors);
}
}
/** * 設置刷新進度條背景色 * see{@link SwipeRefreshLayout#setProgressBackgroundColorSchemeResource(int)} (int)} * @param colorRes */
public void setProgressBackgroundColorSchemeResource(@ColorRes int colorRes) {
if(mSwipeRefreshLayout!=null){
mSwipeRefreshLayout.setProgressBackgroundColorSchemeResource(colorRes);
}
}
/** * 設置刷新進度條背景色 * see{@link SwipeRefreshLayout#setProgressBackgroundColorSchemeColor(int)} * @param color */
public void setProgressBackgroundColorSchemeColor(@ColorInt int color) {
if(mSwipeRefreshLayout!=null){
mSwipeRefreshLayout.setProgressBackgroundColorSchemeColor(color);
}
}
/** * Notify the widget that refresh state has changed. Do not call this when * refresh is triggered by a swipe gesture. * * @param refreshing Whether or not the view should show refresh progress. */
public void setRefreshing(boolean refreshing){
if(mSwipeRefreshLayout== null){
return;
}
mSwipeRefreshLayout.setRefreshing(refreshing);
}
/** * 子類能夠本身指定Adapter,若是不指定默認RVSimpleAdapter * @return */
protected RVSimpleAdapter initAdapter(){
return new RVSimpleAdapter();
}
/** * 子類本身指定RecyclerView的LayoutManager,若是不指定,默認爲LinearLayoutManager,VERTICAL 方向 * @return */
protected RecyclerView.LayoutManager initLayoutManger(){
LinearLayoutManager manager = new LinearLayoutManager(getContext());
manager.setOrientation(LinearLayoutManager.VERTICAL);
return manager;
}
/** * 添加TitleBar * @param */
public View addToolbar(){
//若是須要Toolbar,子類返回Toolbar View
return null;
}
/** *RecyclerView 初始化完畢,能夠在這個方法裏綁定數據 */
public abstract void onRecyclerViewInitialized();
/** * 下拉刷新 */
public abstract void onPullRefresh();
/** * 上拉加載更多 */
public abstract void onLoadMore();
/** * 根據實體生成對應的Cell * @param list 實體列表 * @return cell列表 */
protected abstract List<Cell> getCells(List<T> list);
}複製代碼
AbsBaseFragment,實現了上拉加載和下拉刷新功能,添加Toolbar等,上拉加載能夠自定義View,下拉刷新用的是Google的SwipeRefreshLayout。要添加一個列表界面,只須要繼承AbsBaseFragment,實現幾個抽象方法添加Cell就好了,很是方便。
1,建立一個Fragment繼承AbsBaseFragment,實現幾個方法。
/** * Created by zhouwei on 17/2/3. */
public class HomePageFragment extends AbsBaseFragment<Entry> {
@Override
public void onRecyclerViewInitialized() {
//初始化View和數據加載
}
@Override
public void onPullRefresh() {
//下拉刷新回調
}
@Override
public void onLoadMore() {
//上拉加載回調
}
protected List<Cell> getCells(List<Entry> entries){
//根據實體生成Cell
return null;
}
}複製代碼
實現上面幾個抽象方法,實際上只實現onRecyclerViewInitialized和getCells兩個方法就能夠實現列表,其它兩個方法是下拉刷新和上拉加載的。
2,建立Cell類
/** * Created by zhouwei on 17/2/7. */
public class BannerCell extends RVBaseCell<List<String>> {
public static final int TYPE = 2;
private ConvenientBanner mConvenientBanner;
public BannerCell(List<String> strings) {
super(strings);
}
@Override
public int getItemType() {
return TYPE;
}
@Override
public RVBaseViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
return new RVBaseViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.grid_cell_layoout,null));
}
@Override
public void onBindViewHolder(RVBaseViewHolder holder, int position) {
mConvenientBanner = (ConvenientBanner) holder.getView(R.id.banner);
mConvenientBanner.setPages(new CBViewHolderCreator<NetworkImageHolderView>() {
@Override
public NetworkImageHolderView createHolder() {
return new NetworkImageHolderView();
}
}, mData);
mConvenientBanner.startTurning(2000);
}
@Override
public void releaseResource() {
if(mConvenientBanner!=null){
mConvenientBanner.stopTurning();
}
}
public static class NetworkImageHolderView implements CBPageAdapter.Holder<String>{
private ImageView imageView;
@Override
public View createView(Context context) {
imageView = new ImageView(context);
imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
return imageView;
}
@Override
public void UpdateUI(Context context, int position, String data) {
ImageLoader.getInstance().displayImage(data,imageView);
}
}
}複製代碼
/** * Created by zhouwei on 17/1/19. */
public class ImageCell extends RVBaseCell<Entry> {
public static final int TYPE = 1;
public ImageCell(Entry entry) {
super(entry);
}
@Override
public int getItemType() {
return TYPE;
}
@Override
public RVBaseViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
return new RVBaseViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.image_cell_layout,null));
}
@Override
public void onBindViewHolder(RVBaseViewHolder holder, int position) {
Picasso.with(holder.getItemView().getContext()).load(mData.imageUrl).into(holder.getImageView(R.id.image));
}
}複製代碼
/** * Created by zhouwei on 17/1/19. */
public class TextCell extends RVBaseCell<Entry> {
public static final int TYPE = 0;
public TextCell(Entry entry) {
super(entry);
}
@Override
public int getItemType() {
return TYPE;
}
@Override
public RVBaseViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
return new RVBaseViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.text_cell_layout,null));
}
@Override
public void onBindViewHolder(RVBaseViewHolder holder, int position) {
holder.setText(R.id.text_content,mData.content);
}
}複製代碼
上面建立了3個Cell,也就是這個列表包含了3種不一樣類型的Item。
注意:一個列表內,每一個Cell 的TYPE要不相同,也就是getItemType方法的返回值要不一樣。
3,onRecyclerViewInitialized ,作初始化和加載數據
@Override
public void onRecyclerViewInitialized() {
//初始化View和數據加載
//設置刷新進度條顏色
setColorSchemeResources(R.color.colorAccent);
loadData();
}
/** * 模擬從服務器取數據 */
private void loadData(){
View loadingView = LayoutInflater.from(getContext()).inflate(R.layout.manu_loading_layout,null);
mBaseAdapter.showLoading(loadingView);
mRecyclerView.postDelayed(new Runnable() {
@Override
public void run() {
mBaseAdapter.hideLoading();
mBaseAdapter.addAll(getCells(mockData()));
}
},2000);
}複製代碼
4,實現getCells方法,生成Cell
protected List<Cell> getCells(List<Entry> entries){
//根據實體生成Cell
List<Cell> cells = new ArrayList<>();
cells.add(new BannerCell(Arrays.asList(DataMocker.images)));
for (int i=0;i<entries.size();i++){
Entry entry = entries.get(i);
if(entry.type == Entry.TYPE_IMAGE){
cells.add(new ImageCell(entry));
}else{
cells.add(new TextCell(entry));
}
}
return cells;
}複製代碼
上面根據實體生成不一樣的Cell。有三種Cell,BannerCell,ImageCell和TextCell。
以上4個步驟就能實現一個界面複雜包含多作Item的列表了效果圖以下:
HomePageFragment 的完整代碼以下:
/** * Created by zhouwei on 17/2/3. */
public class HomePageFragment extends AbsBaseFragment<Entry> {
@Override
public void onRecyclerViewInitialized() {
//初始化View和數據加載
//設置刷新進度條顏色
setColorSchemeResources(R.color.colorAccent);
loadData();
}
@Override
public void onPullRefresh() {
//下拉刷新回調
mRecyclerView.postDelayed(new Runnable() {
@Override
public void run() {
setRefreshing(false);
}
},2000);
}
@Override
public void onLoadMore() {
//上拉加載回調
loadMore();
}
private void loadMore(){
mRecyclerView.postDelayed(new Runnable() {
@Override
public void run() {
hideLoadMore();
mBaseAdapter.addAll(getCells(mockMoreData()));
}
},10000);
}
protected List<Cell> getCells(List<Entry> entries){
//根據實體生成Cell
List<Cell> cells = new ArrayList<>();
cells.add(new BannerCell(Arrays.asList(DataMocker.images)));
for (int i=0;i<entries.size();i++){
Entry entry = entries.get(i);
if(entry.type == Entry.TYPE_IMAGE){
cells.add(new ImageCell(entry));
}else{
cells.add(new TextCell(entry));
}
}
return cells;
}
@Override
public View addToolbar() {
View toolbar = LayoutInflater.from(getContext()).inflate(R.layout.title_bar_layout,null);
return toolbar;
}
/** * 模擬從服務器取數據 */
private void loadData(){
View loadingView = LayoutInflater.from(getContext()).inflate(R.layout.manu_loading_layout,null);
mBaseAdapter.showLoading(loadingView);
mRecyclerView.postDelayed(new Runnable() {
@Override
public void run() {
mBaseAdapter.hideLoading();
mBaseAdapter.addAll(getCells(mockData()));
}
},2000);
}
}複製代碼
上面演示了添加多Item type 的列表,添加單Item的列表也是同樣的,只不過只有一個Cell而已。添加Grid 列表和瀑布流列表差很少的,只是RecylerView 的LayoutManager不一樣而已。
瀑布流列表示例:
/** * Created by zhouwei on 17/2/4. */
public class DetailFragment extends AbsBaseFragment<DetailEntry> {
@Override
public void onRecyclerViewInitialized() {
mBaseAdapter.setData(getCells(mockStaggerData()));
}
@Override
public void onPullRefresh() {
}
@Override
public void onLoadMore() {
}
@Override
protected RecyclerView.LayoutManager initLayoutManger() {
StaggeredGridLayoutManager layoutManager = new StaggeredGridLayoutManager(2,StaggeredGridLayoutManager.VERTICAL);
return layoutManager;
}
@Override
protected List<Cell> getCells(List<DetailEntry> list) {
List<Cell> cells = new ArrayList<>();
for (int i=0;i<list.size();i++){
cells.add(new DetailCell(list.get(i)));
}
return cells;
}
}複製代碼
只須要重寫initLayoutManager這個方法,返回一個瀑布流的LayoutMannger就能夠了。
效果以下:
1,顯示LoadMore View
提供了默認的LoadMore View,調用代碼以下:
mBaseAdapter.showLoadMore();複製代碼
若是不想用默認的LoadMore View,固然也能夠自定義LoadMore View,Adapter 提供方法:
mBaseAdapter.showLoadMore(loadMoreView);複製代碼
像上面這樣提供一個LoadMore View 的佈局,還有一個重載的方法,能夠指定顯示的高度:
mBaseAdapter.showLoadMore(loadMoreView,100);複製代碼
若是是繼承的AbsBaseFragment 建立列表,實現customLoadMoreView方法就ok了:
@Override
protected View customLoadMoreView() {
View loadMoreView = LayoutInflater.from(getContext()).inflate(R.layout.custeom_load_more_layout,null);
return loadMoreView;
}複製代碼
隱藏LoadMore View 調用以下代碼:
if(mBaseAdapter!=null){
mBaseAdapter.hideLoadMore();
}複製代碼
效果圖看上面演示的瀑布流效果圖。
2,顯示loading View
提供了默認的Loading View,調用代碼以下:
mBaseAdapter.showLoading();複製代碼
固然也能夠自定義Loading View,提供一個佈局便可:
View loadingView = LayoutInflater.from(getContext()).inflate(R.layout.manu_loading_layout,null);
mBaseAdapter.showLoading(loadingView);複製代碼
效果以下:
還有一種狀況是,頂部有一個固定的HeaderCell,不須要加載數據,顯示靜態頁面,下面加載數據時須要Loading態,Error狀態,Empty狀態等等。提供以下3個方法:
showLoadingKeepCount(int keepCount,int height,View loadingView)
列表Loading狀態顯示的View,保留keepCountg個Item,並指定高度,指定顯示的View
showLoadingKeepCount(int keepCount,int height)
列表Loading狀態顯示的View,保留keepCountg個Item,並指定高度(顯示的是提供的默認Loading View)
showLoadingKeepCount(int keepCount)
顯示默認LoadingView
使用代碼以下:
View loadingView = LayoutInflater.from(getContext()).inflate(R.layout.manu_loading_layout,null);
mBaseAdapter.showLoadingKeepCount(1,height,loadingView);複製代碼
效果圖以下:
隱藏Loading View 調用對應hide 方法:
mBaseAdapter.hideLoading();複製代碼
3, Error View 和 Empty View
顯示Error View 和Empty View 與Loading View 的顯示與隱藏是同樣,不在過多講,直接去看源碼,提供了幾個方法:
Empty View 的顯示徹底同樣,就再也不講了。
以上就是對RecyclerView Adapter 的封裝和 該庫的使用介紹,使用起來很是方便,添加一個列表再也不是重複的寫Adapter,ViewHolder 等等。添加一個Cell 填充到Adapter 就OK。增長一種Item或者加少一種Item對列表徹底沒有影響,耦合度幾乎爲0。詳細的源碼請看Gihub:
Adapter優雅封裝-CustomAdapter,歡迎star和follow。