RecyclerView Adapter in Android

made Fast and Easy字?jǐn)?shù)2326 閱讀79 評論0 喜歡1Fastadapter使RecyclerView更加簡便高效翻譯自文章 http://blog.grafixartist.com/recyclerview-adapter-android-made-fast-easy/使用Android RecyclerView最麻煩的莫過于使用其adapter了莉撇,如果界面再復(fù)雜一些坷澡,adapter里面需要包含多個RecyclerView.ViewHolder就更復(fù)雜了缅阳,這里面還不包括處理各種點(diǎn)擊事件,點(diǎn)擊拖動等等其他一些很酷的功能命锄。如果你正為此發(fā)愁,那么這篇文章就是為你準(zhǔn)備的偏化。當(dāng)然如果你熟悉RecyclerView.Adapter的標(biāo)準(zhǔn)寫法了脐恩,但是簡單的重復(fù)寫相同的代碼是很浪費(fèi)時間的,那有沒有更好的辦法呢侦讨?Say hello to FastAdapter !The bullet proof, fast and easy to use adapter library, which minimizes developing time to a fraction… – Mike Penz穩(wěn)定驶冒、高效、簡單的adapter庫韵卤,能夠有效節(jié)省開發(fā)時間Mike Penz 不僅編寫了FastAdapter骗污,而且還編寫了MaterialDrawer和AboutLibraries兩個比較火的開源庫,F(xiàn)astAdapter中的Demo也有集成這些功能沈条。FastAdapter不僅僅只是減少了你的開發(fā)時間需忿,而且它還提供了許多非常棒的功能,是時候用FastAdapter替換原來簡單形式的RecyclerView Adapters了蜡歹。點(diǎn)擊事件(Click listeners)屋厘,多項(xiàng)選擇(Multi-selection),過濾器(filtering)月而,拖拽功能(drag and drop)汗洒,加入表頭(headers)等等,只要你能說出來的父款,F(xiàn)astAdapter都能提供溢谤。那么,還等什么铛漓?上車吧溯香,騷年!(滴~~~浓恶,學(xué)生卡C堤场!)FastAdapter庫分為核心和擴(kuò)展兩個部分包晰,所以湿镀,在Android Studio中的build.gradle中添加如下依賴:compile('com.mikepenz:fastadapter:1.8.2@aar') {transitive = true}其余擴(kuò)展包在下面的兩個庫中:(我的建議是第一個一定要加炕吸,第二個隨便)compile 'com.mikepenz:fastadapter-extensions:1.8.0@aar'//The tiny Materialize library used for its useful helper classescompile 'com.mikepenz:materialize:1.0.0@aar'最新的配置還請看FastAdapter首頁說明。建立模型類(Creating the Model class)用作者最喜歡的芒果為例勉痴,寫個相關(guān)apppublic class Mango {? ? private String name, description, imageUrl;? ? public Mango() { }? ? public Mango(String name, String description, String imageUrl) {? ? ? ? this.name = name;? ? ? ? this.description = description;? ? ? ? this.imageUrl = imageUrl;? ? }? ? // Your variable Getter Setters here}實(shí)現(xiàn)Adapter(Implementing the Adapter)FastAdapter使用上面你的定義的模型類(model class)來創(chuàng)建RecyclerView.Adapter和RecyclerView.ViewHolder赫模。所以讓你的類實(shí)現(xiàn)AbstractItem這個接口:getType() – 返回一個唯一的ID。這里這個ID一定要是唯一的不能重復(fù)蒸矛,推薦的使用方法是在app/res/values/目錄下新建一個文件瀑罗,在其中指定。參考Android文檔說明雏掠。getLayoutRes() – 返回你布局文件的id斩祭,(R.layout.yours)bindView() – 和RecyclerView的 onBindViewHolder() 方法一樣public class Mango extends AbstractItem{? ? private String name, imageUrl, description;? ? public Mango() { }? ? public Mango(String name, String imageUrl) {? ? ? ? this.name = name;? ? ? ? this.imageUrl = imageUrl;? ? }? ? // Your Getter Setters here? ? // Fast Adapter methods? ? @Override? ? public int getType() { return R.id.item_card; }? ? @Override? ? public int getLayoutRes() { return R.layout.list_item; }? ? @Override? ? public void bindView(ViewHolder holder) {? ? ? ? super.bindView(holder);? ? }? ? // Manually create the ViewHolder class? ? protected static class ViewHolder extends RecyclerView.ViewHolder {? ? ? ? public ViewHolder(View itemView) {? ? ? ? ? ? super(itemView);? ? ? ? }? ? }}綁定FastAdapter到RecyclerView(Marrying FastAdapter to RecyclerView)FastItemAdapterfastAdapter = new FastItemAdapter<>();recyclerView.setAdapter(fastAdapter);// Fetch your data hereListmangoes = loadMangoes();fastAdapter.add(mangoes);就是這么簡單了,這里所做的和普通的RecyclerView.Adapter沒有什么不一樣乡话。來回顧一下我們以前所做的事情摧玫,我們沒有做一下這些建立一個RecyclerView.Adapter的子類加載每一項(xiàng)的布局文件還有煩人的getItemCount()由此可見FastAdapter確實(shí)能夠很方便的建立一個列表。但這還不是全部绑青,F(xiàn)astAdapter還能提供更多的功能诬像。功能列表(Feature List)Let’s see how some popular RecyclerView features are done with FastAdapter. Use the below index to navigate.點(diǎn)擊事件 Click listener數(shù)據(jù)過濾 Filtering data with Search拖拽功能 Drag and drop多項(xiàng)選擇 Multi-select with CAB (Contextual Action Bar) and Undo action添加列表頭 Adding Header view (multiple ViewHolders)無限滾動 Infinite (endless) scrolling1. 點(diǎn)擊事件 Click listenerFastAdapter設(shè)置為可選擇模式后設(shè)置點(diǎn)擊監(jiān)聽fastAdapter.withSelectable(true);fastAdapter.withOnClickListener(new FastAdapter.OnClickListener() {? ? ? ? ? ? @Override? ? ? ? ? ? public boolean onClick(View v, IAdapteradapter, Mango item, int position) {? ? ? ? ? ? ? // Handle click here? ? ? ? ? ? ? ? return true;? ? ? ? ? ? }? ? ? ? });2. 數(shù)據(jù)過濾 Filtering data with Search如果你使用了SearchView,F(xiàn)astAdapter提供了接口可以為你過濾查詢結(jié)果// Call this in your Search listenerfastAdapter.filter("yourSearchTerm");fastAdapter.withFilterPredicate(new IItemAdapter.Predicate() {? ? ? ? ? ? @Override? ? ? ? ? ? public boolean filter(Mango item, CharSequence constraint) {? ? ? ? ? ? ? ? return item.getName().startsWith(String.valueOf(constraint));? ? ? ? ? ? }});留意filter(Mango item, CharSequence constraint)方法闸婴。返回true意味著你要把這些項(xiàng)目從adapter中移除坏挠;如果要保留這些項(xiàng)目在adapter中,移除其他東西邪乍,你需要返回false癞揉。3. 拖拽功能 Drag and drop首先建立一個SimpleDragCallback的實(shí)例,其次用這個實(shí)例初始化ItemTouchHelper,最后把ItemTouchHelper綁定到RecyclerView溺欧。SimpleDragCallback dragCallback = new SimpleDragCallback(this);ItemTouchHelper touchHelper = new ItemTouchHelper(dragCallback);touchHelper.attachToRecyclerView(recyclerView);在Activity中實(shí)現(xiàn)ItemTouchCallback接口喊熟,然后覆蓋itemTouchOnMove()方法@Override? public boolean itemTouchOnMove(int oldPosition, int newPosition) {? ? ? Collections.swap(fastAdapter.getAdapterItems(), oldPosition, newPosition); // change position? ? ? fastAdapter.notifyAdapterItemMoved(oldPosition, newPosition);? ? ? return true;? }4. 多項(xiàng)選擇 Multi-select with CAB (Contextual Action Bar) and Undo action在Activity中建立一個內(nèi)部類ActionBarCallBack,然后讓其實(shí)現(xiàn)ActionMode.Callback接口姐刁。private class ActionBarCallBack implements ActionMode.Callback {? ? ? ? @Override? ? ? ? public boolean onCreateActionMode(ActionMode mode, Menu menu) { return true; }? ? ? ? @Override? ? ? ? public boolean onPrepareActionMode(ActionMode mode, Menu menu) { return false; }? ? ? ? @Override? ? ? ? public boolean onActionItemClicked(ActionMode mode, MenuItem item) {? ? ? ? ? ? mode.finish();? ? ? ? ? ? return true;? ? ? ? }? ? ? ? @Override? ? ? ? public void onDestroyActionMode(ActionMode mode) { }? ? }通過FastAdapter初始化ActionModeHelper芥牌。fastAdapter.setHasStableIds(true);fastAdapter.withSelectable(true);fastAdapter.withMultiSelect(true);fastAdapter.withSelectOnLongClick(true);actionModeHelper = new ActionModeHelper(fastAdapter, R.menu.cab, new ActionBarCallBack());常用的onClick方法用來處理其他事件了,比如說點(diǎn)擊進(jìn)入細(xì)節(jié)展示頁面(detail navigation)聂使。所以FastAdapter提供了兩個新的接口preClick和preLongClick來處理當(dāng)前的選擇點(diǎn)擊事件(CAB)壁拉。fastAdapter.withOnPreClickListener(new FastAdapter.OnClickListener() {? ? ? ? ? ? @Override? ? ? ? ? ? public boolean onClick(View v, IAdapteradapter, Mango item, int position) {? ? ? ? ? ? ? ? Boolean res = actionModeHelper.onClick(item);? ? ? ? ? ? ? ? return res != null ? res : false;? ? ? ? ? ? }});fastAdapter.withOnPreLongClickListener(new FastAdapter.OnLongClickListener() {? ? ? ? ? ? @Override? ? ? ? ? ? public boolean onLongClick(View v, IAdapteradapter, Mango item, int position) {? ? ? ? ? ? ? ? ActionMode actionMode = actionModeHelper.onLongClick(MainActivity.this, position);? ? ? ? ? ? ? ? if (actionMode != null) {? ? ? ? ? ? ? ? ? ? // Set CAB background color? ? ? ? ? ? ? ? ? findViewById(R.id.action_mode_bar).setBackgroundColor(Color.GRAY);? ? ? ? ? ? ? ? }? ? ? ? ? ? ? ? return actionMode != null;? ? ? ? ? ? }});注意,如果Action Mode沒有開啟柏靶,不要處理preClick事件弃理,直接返回false。同時它允許我們處理常規(guī)的點(diǎn)擊事件屎蜓。只是注意當(dāng)你同時使用withOnClickListener()的時候痘昌,也要返回false。最后,在values/styles.xml文件中的AppTheme里開啟windowActionModeOverlay選項(xiàng):true撤銷功能(Undo Action)在CAB模式中刪除項(xiàng)目辆苔,請結(jié)合UndoHelper一起使用算灸。這個類可以幫助我們實(shí)現(xiàn)刪除撤銷功能。UndoHelper undoHelper = new UndoHelper(fastAdapter, new UndoHelper.UndoListener() {? ? ? ? ? ? @Override? ? ? ? ? ? public void commitRemove(Setpositions, ArrayList> removed) {? ? ? ? ? ? ? ? Log.d("remove", "removed: " + removed.size());? ? ? ? ? ? }? ? ? ? });在這個接口的實(shí)現(xiàn)方法中我們記錄了刪除對象的個數(shù)驻啤。UndoHelper.UndoListener同時也能幫助我們得到被刪除對象在列表中的位置菲驴。還記得我們創(chuàng)建的那個內(nèi)部類ActionBarCallBack嗎?我們現(xiàn)在來修改下其中的onActionItemClicked()方法:@Overridepublic boolean onActionItemClicked(ActionMode mode, MenuItem item) {? ? undoHelper.remove(findViewById(android.R.id.content), "Item removed", "Undo", Snackbar.LENGTH_LONG, fastAdapter.getSelections());? ? mode.finish();? ? return true;}UndoHelper的remove()方法骑冗,才是最終執(zhí)行刪除對象的地方赊瞬。刪除執(zhí)行以后會出現(xiàn)一個SnackBar提醒我們刪除成功,同時也給我了我們一個便捷的撤銷最后一次刪除操作的接口贼涩。5. 添加列表頭 Adding Header view (multiple ViewHolders)你可以選擇修改之前創(chuàng)建的Mango類森逮,但是基于代碼整潔的考慮,我們這里新建立一個類去加載Header view磁携。public class Header extends AbstractItem{? ? String title;? ? public Header(String title) {? ? ? ? this.title = title;? ? }? ? // Your getter setters here? ? // AbstractItem methods? ? @Override? ? public int getType() {? ? ? ? return R.id.header_text;? ? }? ? @Override? ? public int getLayoutRes() {? ? ? ? return R.layout.header_item;? ? }? ? @Override? ? public void bindView(ViewHolder holder) {? ? ? ? super.bindView(holder);? ? ? ? holder.textView.setText(title);? ? }? ? protected static class ViewHolder extends RecyclerView.ViewHolder {? ? ? ? @BindView(R.id.header_text) TextView textView;? ? ? ? public ViewHolder(View itemView) {? ? ? ? ? ? super(itemView);? ? ? ? ? ? ButterKnife.bind(this, itemView);? ? ? ? }? ? }}這里的Header只顯示一個簡的單TextView。然后開始實(shí)例化Adapter變量:FastItemAdapter fastAdapter = new FastItemAdapter<>();fastAdapter.setHasStableIds(true);fastAdapter.withSelectable(true);HeaderAdapter

headerAdapter = new HeaderAdapter<>();回憶一下之前我們是如何實(shí)例化FastAdapter的:FastItemAdapterfastAdapter = new FastItemAdapter<>();但是現(xiàn)在我們并沒有直接指定類型良风,這樣可以使用們的FastAdapter同時保存Mango和Header兩種類型谊迄。當(dāng)然你也可以選擇實(shí)例化一個泛型FastAdapter(generic type FastAdapter):FastItemAdapterfastAdapter = new FastItemAdapter<>();IItem是你自定義的Model的基類,所以你可以這樣初始化Adapter烟央,不過要記得在添加數(shù)據(jù)的時候進(jìn)行數(shù)據(jù)轉(zhuǎn)換统诺。組裝adapter(Setting the adapter)這里和之前有點(diǎn)不一樣,我們使用wrap(FastAdapter)方法疑俭,同時把headerAdapter和fastAdapter添加到RecyclerView里粮呢。recyclerView.setAdapter(headerAdapter.wrap(fastAdapter));如果你還想添加第三個不同類型的ViewHolder,同樣可以再使用wrap()方法進(jìn)行钞艇。recyclerView.setAdapter(thirdAdapter.wrap(headerAdapter.wrap(fastAdapter)));添加數(shù)據(jù) Adding data我想在頂部和中間各添加一個Header view啄寡,而每個Header view都應(yīng)該有一個不同的數(shù)據(jù)集。比如說我想添加這樣的數(shù)據(jù):int half = mangoes.size() / 2;fastAdapter.add(0, new Header("First half").withIdentifier(1));fastAdapter.add(1, mangoes.subList(0, half));fastAdapter.add(half + 1, new Header("Second half").withIdentifier(2));fastAdapter.add(half + 2, mangoes.subList(0, half));在上面的代碼中哩照,我把mangoes的前半段數(shù)據(jù)放在了第一個header后面挺物,后半段數(shù)據(jù)放在了第二個header后面。請注意half這個int類型的變量是不斷增加的飘弧,跟其他的List的position一樣识藤。使用不同的ViewHolders (Manipulating with different ViewHolders)現(xiàn)在FastAdapter已經(jīng)包含了幾個不同View和數(shù)據(jù),但是我們?nèi)绾问褂盟鼈兡卮瘟妫勘热缣幚睃c(diǎn)擊痴昧,還有上面介紹的其他酷炫的功能呢?簡單來說冠王,就是使用 Java的關(guān)鍵字:instanceof.下面我將介紹一下如何處理FastAdapter的點(diǎn)擊事件:fastAdapter.withOnClickListener(new FastAdapter.OnClickListener() {? ? ? ? ? ? @Override? ? ? ? ? ? public boolean onClick(View v, IAdapteradapter, IItem item, int position) {? ? ? ? ? ? ? ? if (item instanceof Mango) {? ? ? ? ? ? ? ? ? // Do your thing!? ? ? ? ? ? ? ? } else if (item instanceof Header) {? ? ? ? ? ? ? ? ? // Header clicks usually don't do anything. Ignore if you like.? ? ? ? ? ? ? ? }? ? ? ? ? ? ? ? return true;? ? ? ? ? ? }});看到區(qū)別了嗎赶撰?之前我們使用同樣的監(jiān)聽點(diǎn)擊代碼的時候,onClick()方法傳遞的參數(shù)是Mango類型,但是當(dāng)我們使用了泛型的FastAdapter時扣囊,方法的參數(shù)變成了IItem (基類) 對象乎折。6. 無限滾動 Infinite (endless) scrolling這個功能主要使用在社交類型的app中,每次需要加載指定數(shù)量的信息侵歇,當(dāng)你到達(dá)了信息底部的時候骂澄,出現(xiàn)一個加載標(biāo)志,然后再加載指定數(shù)量的信息惕虑。實(shí)現(xiàn)這個功能的關(guān)鍵就在RecyclerView的addOnScrollListener()方法坟冲。但是我們知道,真正困難的地方就在于構(gòu)建這個監(jiān)聽器溃蔫,基于此健提,F(xiàn)astAdapter為我們提供了EndlessRecyclerOnScrollListener()方法。我們先寫一個FooterAdapter伟叛,我們用這個在列表底部顯示加載數(shù)據(jù)時候的ProgressBar私痹。FooterAdapterfooterAdapter = new FooterAdapter<>();

ProgressItem在FastAdapter extensions庫中,并不是core庫中的類型统刮,所以需要在工程中加載此庫紊遵,前面有說明。

recyclerView.addOnScrollListener(new EndlessRecyclerOnScrollListener() {

@Override

public void onLoadMore(int currentPage) {

footerAdapter.clear();

footerAdapter.add(new ProgressItem().withEnabled(false));

// Load your items here and add it to FastAdapter

fastAdapter.add(newMangoes);

}

});

實(shí)現(xiàn)無限滾動就是這樣簡單侥蒙。So easy暗膜!

寫在最后 (Wrapping it up)

我想這是我最長的一篇文章了!為你們的耐心和堅持鼓掌鞭衩。

RecyclerView的魔力就在于它的Adapter学搜。FastAdapter也著力于此,盡量簡化Adapter的使用论衍,同時致力于提供更多的功能瑞佩,而不僅僅是為了方便使用。如果你需要處理大量Adapter坯台,那么FastAdapter將是不二之選钉凌!

Resources

mikepenz/FastAdapter library on GitHub (library and samples)

Source Code

文章中的代碼可以在我的GitHub Gist找到。

FastAdapter可以讓你輕快地做到普通的RecyclerView能做到的任何事捂人。我已經(jīng)開始在我的工程中使用它了御雕,你準(zhǔn)備好了嗎?在下面的評論中留下你的看法吧滥搭。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末酸纲,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子瑟匆,更是在濱河造成了極大的恐慌闽坡,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,277評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異疾嗅,居然都是意外死亡外厂,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,689評論 3 393
  • 文/潘曉璐 我一進(jìn)店門代承,熙熙樓的掌柜王于貴愁眉苦臉地迎上來汁蝶,“玉大人,你說我怎么就攤上這事论悴∫疵蓿” “怎么了?”我有些...
    開封第一講書人閱讀 163,624評論 0 353
  • 文/不壞的土叔 我叫張陵膀估,是天一觀的道長幔亥。 經(jīng)常有香客問我,道長察纯,這世上最難降的妖魔是什么帕棉? 我笑而不...
    開封第一講書人閱讀 58,356評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮饼记,結(jié)果婚禮上香伴,老公的妹妹穿的比我還像新娘。我一直安慰自己握恳,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,402評論 6 392
  • 文/花漫 我一把揭開白布捺僻。 她就那樣靜靜地躺著乡洼,像睡著了一般。 火紅的嫁衣襯著肌膚如雪匕坯。 梳的紋絲不亂的頭發(fā)上束昵,一...
    開封第一講書人閱讀 51,292評論 1 301
  • 那天,我揣著相機(jī)與錄音葛峻,去河邊找鬼锹雏。 笑死,一個胖子當(dāng)著我的面吹牛术奖,可吹牛的內(nèi)容都是我干的礁遵。 我是一名探鬼主播,決...
    沈念sama閱讀 40,135評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼采记,長吁一口氣:“原來是場噩夢啊……” “哼佣耐!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起唧龄,我...
    開封第一講書人閱讀 38,992評論 0 275
  • 序言:老撾萬榮一對情侶失蹤兼砖,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體讽挟,經(jīng)...
    沈念sama閱讀 45,429評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡懒叛,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,636評論 3 334
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了耽梅。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片薛窥。...
    茶點(diǎn)故事閱讀 39,785評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖褐墅,靈堂內(nèi)的尸體忽然破棺而出拆檬,到底是詐尸還是另有隱情,我是刑警寧澤妥凳,帶...
    沈念sama閱讀 35,492評論 5 345
  • 正文 年R本政府宣布竟贯,位于F島的核電站,受9級特大地震影響逝钥,放射性物質(zhì)發(fā)生泄漏屑那。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,092評論 3 328
  • 文/蒙蒙 一艘款、第九天 我趴在偏房一處隱蔽的房頂上張望持际。 院中可真熱鬧,春花似錦哗咆、人聲如沸蜘欲。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,723評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽姥份。三九已至,卻和暖如春年碘,著一層夾襖步出監(jiān)牢的瞬間澈歉,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,858評論 1 269
  • 我被黑心中介騙來泰國打工屿衅, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留埃难,地道東北人。 一個月前我還...
    沈念sama閱讀 47,891評論 2 370
  • 正文 我出身青樓涤久,卻偏偏與公主長得像涡尘,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子响迂,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,713評論 2 354

推薦閱讀更多精彩內(nèi)容