1. 程式人生 > >RecyclerView 之通用適配

RecyclerView 之通用適配

RecyclerView 是Android L版本中新新增的一個用來取代ListView的SDK,它的靈活性與可替代性比listview更好。RecyclerView 同樣也用到適配,枯燥重複的適配肯定會讓你不勝其煩,下面讓我們一起來打造一款通用的適配(BaseQuickAdapter)。受益群體幾乎是所有Android開發者,希望更你們能夠一起來維護這個專案,把這個專案做得更好,幫助更多人。

看到這裡你肯定會有疑問,通用適配(BaseQuickAdapter),它具體能夠做些什麼呢,或者說它都有哪些功能?

這裡非常感謝 陳宇明

本文結合他文章和我的一些修改,希望大家能夠喜歡。

一、BaseQuickAdapter 簡介

  • 減少重複 Adapter 程式碼

  • 新增 Item 的點選事件,長按事件以及子控制元件的點選事件

  • 新增頭部、尾部,下拉重新整理、上拉載入(上拉載入的5種載入更多動畫任你選擇,後期會新增更多的載入動畫)、沒有更多資料

  • 可以自定義頭部、尾部、載入更多佈局

  • 新增 Item滑動動畫 (9種動畫切換,輕鬆一行程式碼)

  • 新增新增、刪除 Item動畫 (目前支援預設的動畫方式)

  • 網格,列表,流式隨意切換

  • 新增空佈局(列表無資料時,顯示更加人性化)

  • 拖拽和側滑刪除

  • 支援多型別佈局

  • 類似淘寶列表切換

  • 字母導航

  • 類似探探翻牌

看了 BaseQuickAdapter 的特性,接著來看看外面如何在專案中匯入(依賴)它。

BaseQuickAdapter 匯入(依賴)

方式一:build.gradle 的 dependencies 新增如下程式碼:

//最新程式碼還沒更新到 jcenter 倉庫,推薦使用方法二依賴專案
compile 'com.github.baserecycleradapter:library:1.1.0'

方式二:下載原始碼,新增 library 庫到你專案當中。

這裡推薦使用方法二依賴進專案。

BaseQuickAdapter 使用

mRecyclerView.setAdapter(mAdapter = new BaseQuickAdapter<String, BaseViewHolder>(R.layout.rv_item, getItemDatas()) {
    @Override
protected void convert(final BaseViewHolder helper, String item) { helper.setText(R.id.tv_item_text, item); } });

recy

Item點選,長按事件

//Item 點選事件
setOnItemClickListener(int viewId, AdapterView.OnItemClickListener listener)

//長按事件
setOnItemLongClickListener(int viewId, AdapterView.OnItemLongClickListener listener)

recy

子控制元件的點選事件

   helper.setOnClickListener(R.id.tv_item_text, new View.OnClickListener() {
       @Override
       public void onClick(View v) {
          //事件處理
       }
   });

新增頭部,尾部

    //頭部
    mAdapter.addHeaderView();

    //尾部
    mAdapter.addFooterView();

以下是新增頭部的程式碼:

View headerView=getLayoutInflater().inflate(R.layout.rv_header, null);

headerView.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,ViewGroup.LayoutParams.WRAP_CONTENT));

mAdapter.addHeaderView(headerView);

recy

部的新增與頭部的新增類似。

新增 Item動畫

recy

 //一行程式碼開啟動畫 預設CUSTOM動畫
  mAdapter.openLoadAnimation(BaseQuickAdapter.CUSTOMIN);

當然你可以更換其他動畫:

//ALPHAIN, SCALEIN, SLIDEIN_BOTTOM, SLIDEIN_LEFT, SLIDEIN_RIGHT, //SLIDEIN_LEFT_RIGHT, SLIDEIN_BOTTOM_TOP, CUSTOMIN
mAdapter.openLoadAnimation(BaseQuickAdapter.CUSTOMIN);

最後你可以自定義 Item動畫:

mAdapter.openLoadAnimation(new BaseAnimation[]{
        new BaseAnimation() {
            @Override
            public Animator[] getAnimators(View view) {
                return new Animator[]{ObjectAnimator.ofFloat(view, "alpha", 0.5f, 1.0f),
                        ObjectAnimator.ofFloat(view, "scaleX", 0.5f, 1.0f)};
            }
        }
});

設定載入更多

只需要設定載入更多介面,就可以實現載入更多功能。

    mAdapter.setOnLoadMoreListener(new BaseQuickAdapter.RequestLoadMoreListener() {
        @Override
        public void onLoadMoreRequested() {
        }
    });

recy

以下演示正在載入中,載入失敗點選重試,載入完成等狀態:

    mShowType++;
    if (mShowType == 2) {
        mHandler.postDelayed(new Runnable() {
            @Override
            public void run() {
                //載入失敗,點選重試
                mAdapter.loadMoreFail();
            }
        }, DELAY_MILLIS);
    } else if (mShowType >= 4) {
        mHandler.post(new Runnable() {
            @Override
            public void run() {
                //載入完成
                mAdapter.loadMoreEnd();
            }
        });
    } else {
        mHandler.postDelayed(new Runnable() {
            @Override
            public void run() {
                mAdapter.addData(addDatas());
                //載入更多完成
                mAdapter.loadMoreComplete();
            }
        }, DELAY_MILLIS);
    }

你可以設定載入更多型別,只需要新增一行程式碼,實現不同的載入更多動畫:

  //設定載入更多 loadingview 
 setLoadMoreType(@LoadMoreType int loadMoreType)

這裡有四種模式供你選擇,APAY, BALL_BEAT, BALL_CLIP_ROTATE, BALL_SCALE,如果都不滿足你的需求,你可以繼承 BaseIndicator類從新載入檢視,或給我留言。

新增空佈局

    View emptyView=getLayoutInflater().inflate(R.layout.rv_empty, null);
    emptyView.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
            ViewGroup.LayoutParams.MATCH_PARENT));
    //新增空檢視
    mAdapter.setEmptyView(emptyView);

    emptyView.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            Snackbar.make(view, "your click empty", Snackbar.LENGTH_SHORT).show();
        }
    });

recy

拖拽和側滑

新增以下程式碼:

ItemTouchHelper.Callback callback = new SimpleItemTouchHelperCallback(mAdapter);

ItemTouchHelper mItemTouchHelper = new ItemTouchHelper(callback);

mAdapter.setItemTouchHelper(mItemTouchHelper);

mAdapter.setDragViewId(R.id.iv_drag);

mItemTouchHelper.attachToRecyclerView(mRecyclerView);

recycler

支援不同型別

mRecyclerView.setAdapter(mAdapter = new BaseMultiItemAdapter<MultiItem>(this, getMultiItemDatas()) {
    @Override
    protected void convert(BaseViewHolder helper, MultiItem item) {
        switch (helper.getItemViewType()) {
            case MultiItem.SEND:
                helper.setText(R.id.chat_from_content, item.content);
                //helper.setImageBitmap(R.id.chat_from_icon,getRoundCornerBitmap(BitmapFactory.decodeResource(getResources(), R.mipmap.chat_head), 16));
                break;
            case MultiItem.FROM:
                helper.setText(R.id.chat_send_content, item.content);
                //helper.setImageBitmap(R.id.chat_send_icon,getRoundCornerBitmap(BitmapFactory.decodeResource(getResources(), R.mipmap.from_head), 16));
                break;
        }
    }
    @Override
    protected void addItemLayout() {
        addItemType(MultiItem.SEND, R.layout.chat_send_msg);
        addItemType(MultiItem.FROM, R.layout.chat_from_msg);
    }
});
mAdapter.openLoadAnimation(true);
btnSend.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View view) {
        MultiItem multiItem = new MultiItem();
        multiItem.itemType = MultiItem.SEND;
        multiItem.content = etChat.getText().toString();
        mAdapter.add(multiItem);
        mRecyclerView.smoothScrollToPosition(mAdapter.getItemCount());
        //mRecyclerView.scrollToPosition(mAdapter.getItemCount() - 1);
    }
});

資料來源:

public static List<MultiItem> getMultiItemDatas() {
    List<MultiItem> list = new ArrayList<>();
    for (int i = 0; i < 100; i++) {
        MultiItem multiItem = new MultiItem();
        if (i % 2 == 0) {
            multiItem.itemType = MultiItem.SEND;
            multiItem.content = "海,妹子約嗎";
        } else {
            multiItem.itemType = MultiItem.FROM;
            multiItem.content = "大哥,你別怕";
        }
        list.add(multiItem);
    }
    return list;
}

recycler

這樣就輕鬆實現了聊天介面。

這樣簡單的配置就可以實現多型別佈局,不需要你寫格外的程式碼。

流式佈局

先來看看效果圖:

flow

一行程式碼實現流式佈局效果:

mRecyclerView.setLayoutManager(new FlowLayoutManager());

探探翻牌

類似流式效果,重寫 LayoutManager 實現翻牌效果:

 mRecyclerView.setLayoutManager(new OverLayCardLayoutManager());

//新增 itemTouchHelper

    final TanTanCallback callback = new TanTanCallback(mRecyclerView, mAdapter, mAdapter.getData());
    //測試豎直滑動是否已經不會被移除螢幕
    //callback.setHorizontalDeviation(Integer.MAX_VALUE);
    final ItemTouchHelper itemTouchHelper = new ItemTouchHelper(callback);
    itemTouchHelper.attachToRecyclerView(mRecyclerView);

效果圖一覽:

tantan

具體實現請參考 Demo

淘寶商品列表切換

先來看看效果圖:

taobao

看看程式碼的實現:

        //線性
        if (mIsLinearManager) {
            mAdapter.setLayoutType(BaseQuickAdapter.TRANS_0_VIEW);
            mRecyclerView.setLayoutManager(new LinearLayoutManager(this));
        } else {
            //網格
            mAdapter.setLayoutType(BaseQuickAdapter.TRANS_1_VIEW);
            mRecyclerView.setLayoutManager(new GridLayoutManager(this, 2));
            //需要顯示載入更多則加上下面這句   從新關聯recycler
            mAdapter.onAttachedToRecyclerView(mRecyclerView);
        }
        mIsLinearManager = !mIsLinearManager;

注意:最多支援3種不同型別的轉換。

單選

實現單選,有好幾位同仁都在問我,其實實現單選是比較簡單的,方案也比較多,我這裡就不在細講了。下面我給出一種實現方案:

    public void setItemChecked(int position) {
        if (mLastCheckedPosition == position)
            return;

        mBooleanArray.put(position, true);

        if (mLastCheckedPosition > -1) {
            mBooleanArray.put(mLastCheckedPosition, false);
            mAdapter.notifyItemChanged(mLastCheckedPosition);
        }

        mAdapter.notifyDataSetChanged();

        mLastCheckedPosition = position;
    }

mBooleanArray 儲存是否被點選,把點選前的索引值置為 false , 點選索引置為 true 。

sel

敬請大家的關注,後期會一直維護本庫,有什麼好的想法,可以提出來。我們互相學習進度。 下一個版本會自定義下拉重新整理,全新多項的重新整理貢大家喜歡。再次感謝大家一直對我的關注,新年將近,祝願大家新年新氣象,新年大吉!

原始碼傳送門

如果對你有所幫助請給star

歡迎加入478720016來幫助更多的人。

相關推薦

RecyclerView 通用

RecyclerView 是Android L版本中新新增的一個用來取代ListView的SDK,它的靈活性與可替代性比listview更好。RecyclerView 同樣也用到適配,枯燥重複的適配肯定會讓你不勝其煩,下面讓我們一起來打造一款通用的適配(Bas

dubbo日誌及訪問日誌

訪問日誌 DDU ring toc accesslog span rate slf4j spa 日誌適配 自 2.2.1 開始,dubbo 開始內置 log4j、slf4j、jcl、jdk 這些日誌框架的適配 1,也可以通過以下方式顯示配置日誌輸出策略: 命令行

Android 螢幕 dimens

相信做手機端的 App 的小夥伴,只要是產品稍微大一點,就會面臨螢幕適配的問題,對於適配這個問題,網上眾說紛紜,以前雖然有零零散散的看過,但是沒有實踐過,也是在最近遇到這個需求的情況下才研究了一下,現在做個記錄。 1 參考連結 http://blog.csdn.net/qq_341

Android中ListView、GridView的通用封裝簡化程式碼

轉載請註明出處:http://blog.csdn.net/u013038616/article/details/50733935 ListView和GridView是我們平時經常用來展示集合資料,每次都要為每種列表建一個專門的適配,雖然建立介面卡灰常簡單,但是每次都會有很多類似的程式碼,作

Android修煉Pie 的搬運工

自嘲時刻 Android P正式版(以下稱為Pie)已經正式上線了,各大廠商已經開始了系統升級工作,咱做上層開發的也得跟上節奏。當然了,新版本所有的行為更改內容都可以在官網上找到,對於其中如何繞開非SDK介面限制的問題,也有各路大神給出瞭解決方案。所以,我只能當

Android APP全方位效能調優螢幕終結者

優點 1. 無侵入性 首先科普下 Android 中的一個長度單位:pt,它表示一個點,是螢幕的物理尺寸,其大小為 1 英寸的 1 / 72,也就是 72pt 等於 1 英寸(其實 Android 中還有比較少見的 in 和 mm 的長度單位)。而我本次的適配使用的單位恰好是 pt,所以對你

Android機型

Android中的機型適配 在軟體開發的過程中,為了讓軟體在不同的場景下都可以使用,所以機型適配是不可或缺並且非常重要耗時的一個環節. 一:機型適配需要考慮的幾個方面: 1,Android的版本 2.手機廠商 3.螢幕的尺寸 4.網路的制式 5

android螢幕(三)實踐dimens.xml尺寸不同的平板

android3.2以後,為了提供更精準的對佈局檔案的控制,可以通過為資原始檔(res目錄下檔案)增加字尾來指定該資料夾裡的xml佈局檔案或color.xml,string.xml是為哪種大小的螢幕使用。 第一種字尾:sw<N>dp,如layout-sw600

Android螢幕

        網上螢幕適配的方式有很多,比如按百分比的、按解析度的,這裡我是按最小寬度去適配,也是Google建議的方式。         1.首先下載螢幕適配外掛ScreenMatch。         AS→File→Settings→plugins→SreenMa

android 手機valuesdimen值

android 適配螢幕的方式有很多,最方便最直接的無非就是適配values裡的dimens檔案值來進行適配. 張鴻洋大神已經寫過一篇適配的文章,很詳細 但是我在閱讀的時候還是有點疑問,這個values-1920x1080到底是dp值還是手機解析度,因為我在

React Native入門(十一)螢幕

準備 首先,我們在官方文件寬度和高度一節可以知道,RN中單位是dp,這個跟Android中的單位是一致的! 官網中: A dp is equal to one physical pixel on a screen with a density of 1

Swift動態UITableView的cell高度

首先在Xib中拖一個UITableView,讓其充滿整個檢視控制器,並遵守實現UITableViewDelegate,UITableViewDataSource協議; 其次,新建一個繼承於UItabl

Android筆記螢幕全攻略

Android螢幕適配出現的原因 在我們學習如何進行螢幕適配之前,我們需要先了解下為什麼Android需要進行螢幕適配。 由於Android系統的開放性,任何使用者、開發者、OEM廠商、運營商都可以對Android進行定製,修改成他們想要的樣子。

cocos2dx進階學習螢幕

背景在學習cocos2dx時,我們在main函式中發現一句程式碼,#include "main.h" #include "AppDelegate.h" #include "CCEGLView.h" USING_NS_CC; int APIENTRY _tWinMain(H

Android知識梳理螢幕全攻略

       引言: 我相信Android碎片化問題是讓所有的Android開發者都比較頭疼的問題.尤其是螢幕適配這一塊兒.想要自己的app在不同的裝置上面都有一個比較好的顯示效果.就必須做好相應的螢幕適配.本文是結合網上的相關知識總結、官方文件結合自己的一些理解來進行闡述

原始碼分析 Sentinel Dubbo 原理

在Alibaba Sentinel 限流與熔斷初探(技巧篇) 的示例中我選擇了 sentinel-demo-apache-dubbo 作為突破點,故本文就從該專案入手,看看 Sentinel 是如何對 Dubbo 做的適配,讓專案使用方無感知,只需要引入對應的依即可。 sentinel-apache-dubb

android實現萬能RecyclerView的adapter

現在基本大家都推薦RecyclerView,很少有人使用ListView了,包括我自己也是,已經很久沒用ListView了,所以關於ListView的萬能adapter就不寫了。 每次寫專案的時候,每次遇到RecyclerView都要重新寫一個Adapter,

通用recyclerview adapter

統一管理適配Adapter多型別處理,更加方便的管理和操作。 joe 偉大的地獄逃脫者 讓我來和你講個故事,關於joe 的MyLittleZoo公司 。關於他是怎麼創造可複用的不同型別的Recyclerview adapter來終結他的噩夢。和他最終

xcode7和ios9

get sans att 新建 技術分享 matching resolve down 二進制 從xcode6.x升級xcode7.2之後,發現要做一堆事情來做適配,不然之前的項目沒法好好執行。 一.換庫 dylib後綴的庫都要換成tbd後綴的。例如以下所看到的

移動端rem 筆記

mcal ont padding 字體大小 頁面 所有 1.2 resize 筆記 /*移動端適配 width|height|font-size = 視覺稿量出來的值 / 100rem;@lbl*/ @media screen and (max-width:359px)