BRVAH官方使用指南(持續(xù)更新)

www.recyclerview.org

官方網(wǎng)站:www.recyclerview.org

BRVAH是一個(gè)強(qiáng)大的RecyclerAdapter框架(什么是RecyclerView?),它能節(jié)約開(kāi)發(fā)者大量的開(kāi)發(fā)時(shí)間,集成了大部分列表常用需求解決方案。為什么會(huì)有它?請(qǐng)查看「Android開(kāi)源框架BRVAH由來(lái)篇」該框架于2016年4月10號(hào)發(fā)布的第1個(gè)版本到現(xiàn)在已經(jīng)一年多了,經(jīng)歷了800多次代碼提交,140多次版本打包,修復(fù)了1000多個(gè)問(wèn)題,獲得了9000多star,非常感謝大家的使用以及反饋。
本篇為BRVAH的使用指南以及包含常見(jiàn)問(wèn)題會(huì)第一時(shí)間更新最新的使用方法。最新版本請(qǐng)查看releases,由于持續(xù)更新。

文章目錄

  • 框架引入
  • 優(yōu)化Adapter代碼
    和原始的adapter相對(duì),減少70%的代碼量。
  • 添加Item事件
    Item的點(diǎn)擊事件
    Item的長(zhǎng)按事件
    Item子控件的點(diǎn)擊事件
    Item子控件的長(zhǎng)按事件
  • 添加列表加載動(dòng)畫
    一行代碼輕松切換5種默認(rèn)動(dòng)畫。
  • 添加頭部、尾部
    一行代碼搞定,感覺(jué)又回到ListView時(shí)代。
  • 自動(dòng)加載
    上拉加載無(wú)需監(jiān)聽(tīng)滑動(dòng)事件,可自定義加載布局,顯示異常提示,自定義異常提示。同時(shí)支持下拉加載。
  • 分組布局
    隨心定義分組頭部。
  • 多布局
    簡(jiǎn)單配置、無(wú)需重寫額外方法。
  • 設(shè)置空布局
    比Listview的setEmptyView還要好用。
  • 添加拖拽、滑動(dòng)刪除
    開(kāi)啟,監(jiān)聽(tīng)即可,就是這么簡(jiǎn)單。
  • 樹(shù)形列表
    比ExpandableListView還要強(qiáng)大,支持多級(jí)。
  • 自定義ViewHolder
    支持自定義ViewHolder,讓開(kāi)發(fā)者隨心所欲。
  • 擴(kuò)展框架
    組合第三方框架,輕松實(shí)現(xiàn)更多需求定制。

框架引入

先在 build.gradle(Project:XXXX) 的 repositories 添加:

    allprojects {
        repositories {
            ...
            maven { url "https://jitpack.io" }
        }
    }

然后在 build.gradle(Module:app) 的 dependencies 添加:

    dependencies {
            compile 'com.github.CymChad:BaseRecyclerViewAdapterHelper:2.9.30'
    }

更新說(shuō)明:https://github.com/CymChad/BaseRecyclerViewAdapterHelper/releases

注意

版本:2.9.28
Change the method setVisible --> setGone
The new method setVisible

setVisible:Set a view visibility to VISIBLE (true) or INVISIBLE (false).
setGone: Set a view visibility to VISIBLE (true) or GONE (false).

注意: 一旦出現(xiàn)加載失敗的情況,只有兩種情況:

  1. 配置沒(méi)配置好
    配置沒(méi)配置好,有幾種情況:
    1. 只配置了dependencies
    2. 配置repositories,但是位置錯(cuò)了,build.gradle(Project:XXXX) 文件下的repositories有兩個(gè),一個(gè)是buildscript下面的,一個(gè)是allprojects下面的,要配置到allprojects下面才是對(duì)的。
    3. 版本號(hào)前面多一個(gè)v,這個(gè)是我的鍋,在2.1.2版本之前都是帶v的,之后(包含2.1.2)都不需要帶v。
  2. 網(wǎng)絡(luò)原因(這個(gè)就不解釋了)

使用Adapter

和原始的adapter相對(duì),減少70%的代碼量。

使用代碼

public class HomeAdapter extends BaseQuickAdapter<HomeItem, BaseViewHolder> {
    public HomeAdapter(int layoutResId, List data) {
        super(layoutResId, data);
    }

    @Override
    protected void convert(BaseViewHolder helper, HomeItem item) {
        helper.setText(R.id.text, item.getTitle());
        helper.setImageResource(R.id.icon, item.getImageResource());
        // 加載網(wǎng)絡(luò)圖片
      Glide.with(mContext).load(item.getUserAvatar()).crossFade().into((ImageView) helper.getView(R.id.iv));
    }
}

注:如果想深入了解的原理可以查看RecyclerView.Adapter優(yōu)化了嗎?

使用

首先需要繼承BaseQuickAdapter,然后BaseQuickAdapter<Status, BaseViewHolder>第一個(gè)泛型Status是數(shù)據(jù)實(shí)體類型,第二個(gè)BaseViewHolder是ViewHolder其目的是為了支持?jǐn)U展ViewHolder。

賦值

可以直接使用viewHolder對(duì)象點(diǎn)相關(guān)方法通過(guò)傳入viewId和數(shù)據(jù)進(jìn)行,方法支持鏈?zhǔn)秸{(diào)用。如果是加載網(wǎng)絡(luò)圖片或自定義view可以通過(guò)viewHolder.getView(viewId)獲取該控件。

常用方法

  • viewHolder.getLayoutPosition() 獲取當(dāng)前item的position

常見(jiàn)問(wèn)題

這些問(wèn)題不是使用該庫(kù)的問(wèn)題,但是經(jīng)常有人問(wèn)這些問(wèn)題,所以特意寫出來(lái),幫助后續(xù)遇到以下問(wèn)題的開(kāi)發(fā)者們。

為什么有數(shù)據(jù)不顯示?
請(qǐng)檢查一下你的RecyclerView是否設(shè)置了LayoutManager。

為什么有10條數(shù)據(jù),只顯示1條?
請(qǐng)檢查一下item的布局最外層的Layout是不是layout_height設(shè)置了match_parent.

數(shù)據(jù)狀態(tài)錯(cuò)亂
這個(gè)問(wèn)題無(wú)論是RecyclerView還是ListView不做處理都會(huì)出現(xiàn)問(wèn)題,這個(gè)本質(zhì)上是由于布局重用機(jī)制導(dǎo)致的,解決辦法是通過(guò)數(shù)據(jù)狀態(tài)來(lái)控制控件的狀態(tài),一定要設(shè)置狀態(tài)無(wú)論什么狀態(tài),ifelse是少不了的,如下代碼:

  if(entity.isCheck){
    checkBox.isChecked(true);
  } else {
    checkBox.isChecked(false);
  }

解決緩存問(wèn)題案例:

添加Item事件


Item的點(diǎn)擊事件

adapter.setOnItemClickListener(new BaseQuickAdapter.OnItemClickListener() {
            @Override
            public void onItemClick(BaseQuickAdapter adapter, View view, int position) {
                Log.d(TAG, "onItemClick: ");
                Toast.makeText(ItemClickActivity.this, "onItemClick" + position, Toast.LENGTH_SHORT).show();
            }
        });

Item的長(zhǎng)按事件

adapter.setOnItemLongClickListener(new BaseQuickAdapter.OnItemLongClickListener() {
            @Override
            public boolean onItemLongClick(BaseQuickAdapter adapter, View view, int position) {
                Log.d(TAG, "onItemLongClick: ");
                Toast.makeText(ItemClickActivity.this, "onItemLongClick" + position, Toast.LENGTH_SHORT).show();
                return false;
            }
        });

注意:嵌套recycleView的情況下需要使用你使用 adapter. setOnItemClickListener 來(lái)設(shè)置點(diǎn)擊事件,如果使用recycleView.addOnItemTouchListener會(huì)累計(jì)添加的。

Item子控件的點(diǎn)擊事件
首先在adapter的convert方法里面通過(guò)viewHolder.addOnClickListener綁定一下的控件id

 @Override
    protected void convert(BaseViewHolder viewHolder, Status item) {
        viewHolder.setText(R.id.tweetName, item.getUserName())
                .setText(R.id.tweetText, item.getText())
                .setText(R.id.tweetDate, item.getCreatedAt())
                .setVisible(R.id.tweetRT, item.isRetweet())
                .addOnClickListener(R.id.tweetAvatar)
                .addOnClickListener(R.id.tweetName)
                .linkify(R.id.tweetText);
       
    }

然后在設(shè)置

 adapter.setOnItemChildClickListener(new BaseQuickAdapter.OnItemChildClickListener() {
            @Override
            public boolean onItemChildClick(BaseQuickAdapter adapter, View view, int position) {
                Log.d(TAG, "onItemChildClick: ");
                Toast.makeText(ItemClickActivity.this, "onItemChildClick" + position, Toast.LENGTH_SHORT).show();
                return false;
            }
        });

Item子控件的長(zhǎng)按事件
步驟同上使用方法不同。
adapter中綁定方法將addOnClickListener改成addOnLongClickListener.
設(shè)置點(diǎn)擊事件方法setOnItemChildClickListener改成setOnItemChildLongClickListener

注意:設(shè)置子控件的事件,如果不在adapter中綁定,點(diǎn)擊事件無(wú)法生效,因?yàn)闊o(wú)法找到你需要設(shè)置的控件。

如果需要在點(diǎn)擊事件中獲取其他子控件可以使用:

getViewByPosition(RecyclerView recyclerView, int position, @IdRes int viewId) 

注意:如果有header的話需要處理一下position加上 headerlayoutcount。

添加列表加載動(dòng)畫

開(kāi)啟動(dòng)畫(默認(rèn)為漸顯效果)
adapter.openLoadAnimation();
默認(rèn)提供5種方法(漸顯、縮放、從下到上,從左到右、從右到左)

public static final int ALPHAIN = 0x00000001;
    /**
     * Use with {@link #openLoadAnimation}
     */
    public static final int SCALEIN = 0x00000002;
    /**
     * Use with {@link #openLoadAnimation}
     */
    public static final int SLIDEIN_BOTTOM = 0x00000003;
    /**
     * Use with {@link #openLoadAnimation}
     */
    public static final int SLIDEIN_LEFT = 0x00000004;
    /**
     * Use with {@link #openLoadAnimation}
     */
    public static final int SLIDEIN_RIGHT = 0x00000005;

切換動(dòng)畫

quickAdapter.openLoadAnimation(BaseQuickAdapter.ALPHAIN);

自定義動(dòng)畫

quickAdapter.openLoadAnimation(new BaseAnimation() {
                            @Override
                            public Animator[] getAnimators(View view) {
                                return new Animator[]{
                                        ObjectAnimator.ofFloat(view, "scaleY", 1, 1.1f, 1),
                                        ObjectAnimator.ofFloat(view, "scaleX", 1, 1.1f, 1)
                                };
                            }
                        });

動(dòng)畫默認(rèn)只執(zhí)行一次,如果想重復(fù)執(zhí)行可設(shè)置

mQuickAdapter.isFirstOnly(false);

注:如果想深入了解的原理可以查看BaseRecyclerAdapter之添加動(dòng)畫(策略模式)

設(shè)置不顯示動(dòng)畫數(shù)量

adapter.setNotDoAnimationCount(count);

首次到界面的item都依次執(zhí)行加載動(dòng)畫

由于進(jìn)入界面的item都是很多的速度進(jìn)來(lái)的所以不會(huì)出現(xiàn)滑動(dòng)顯示的依次執(zhí)行動(dòng)畫效果,這個(gè)時(shí)候會(huì)一起執(zhí)行動(dòng)畫,如果覺(jué)得這樣的效果不好可以使用setNotDoAnimationCount設(shè)置第一屏item不執(zhí)行動(dòng)畫,但是如果需要依次執(zhí)行動(dòng)畫可以重寫startAnim讓第一個(gè)屏幕的item動(dòng)畫延遲執(zhí)行即可。

@Override
    protected void startAnim(Animator anim, int index) {
        super.startAnim(anim, index);
        if (index < count)
        anim.setStartDelay(index * 150);
    }

添加頭部、尾部


添加

mQuickAdapter.addHeaderView(getView());
mQuickAdapter.addFooterView(getView());

注:如果想深入了解的原理可以查看BaseRecyclerAdapter之添加不同布局(頭部尾部)

刪除指定view

mQuickAdapter.removeHeaderView(getView);
mQuickAdapter.removeFooterView(getView);

刪除所有

mQuickAdapter.removeAllHeaderView();
mQuickAdapter.removeAllFooterView();

默認(rèn)出現(xiàn)了頭部就不會(huì)顯示Empty,和尾部,配置以下方法也支持同時(shí)顯示:

setHeaderAndEmpty
setHeaderFooterEmpty

默認(rèn)頭部尾部都是占滿一行,如果需要不占滿可以配置:

setHeaderViewAsFlow
setFooterViewAsFlow

自動(dòng)加載

上拉加載


// 滑動(dòng)最后一個(gè)Item的時(shí)候回調(diào)onLoadMoreRequested方法
setOnLoadMoreListener(RequestLoadMoreListener);

默認(rèn)第一次加載會(huì)進(jìn)入回調(diào),如果不需要可以配置:

mQuickAdapter.disableLoadMoreIfNotFullPage();

回調(diào)處理代碼

mQuickAdapter.setOnLoadMoreListener(new BaseQuickAdapter.RequestLoadMoreListener() {
            @Override public void onLoadMoreRequested() {
                mRecyclerView.postDelayed(new Runnable() {
                    @Override
                    public void run() {
                        if (mCurrentCounter >= TOTAL_COUNTER) {
                            //數(shù)據(jù)全部加載完畢
                            mQuickAdapter.loadMoreEnd();
                        } else {
                            if (isErr) {
                                //成功獲取更多數(shù)據(jù)
                                mQuickAdapter.addData(DataServer.getSampleData(PAGE_SIZE));
                                mCurrentCounter = mQuickAdapter.getData().size();
                                mQuickAdapter.loadMoreComplete();
                            } else {
                                //獲取更多數(shù)據(jù)失敗
                                isErr = true;
                                Toast.makeText(PullToRefreshUseActivity.this, R.string.network_err, Toast.LENGTH_LONG).show();
                                mQuickAdapter.loadMoreFail();

                            }
                        }
                    }

                }, delayMillis);
            }
        }, mReyclerView);

加載完成(注意不是加載結(jié)束,而是本次數(shù)據(jù)加載結(jié)束并且還有下頁(yè)數(shù)據(jù))

mQuickAdapter.loadMoreComplete();

加載失敗

mQuickAdapter.loadMoreFail();

加載結(jié)束

mQuickAdapter.loadMoreEnd();

注意:如果上拉結(jié)束后,下拉刷新需要再次開(kāi)啟上拉監(jiān)聽(tīng),需要使用setNewData方法填充數(shù)據(jù)。

打開(kāi)或關(guān)閉加載(一般用于下拉的時(shí)候做處理,因?yàn)樯侠吕荒芡瑫r(shí)操作)

mQuickAdapter.setEnableLoadMore(boolean);

預(yù)加載

// 當(dāng)列表滑動(dòng)到倒數(shù)第N個(gè)Item的時(shí)候(默認(rèn)是1)回調(diào)onLoadMoreRequested方法
mQuickAdapter.setPreLoadNumber(int);

設(shè)置自定義加載布局

mQuickAdapter.setLoadMoreView(new CustomLoadMoreView());
public final class CustomLoadMoreView extends LoadMoreView {

    @Override public int getLayoutId() {
        return R.layout.view_load_more;
    }

    /**
     * 如果返回true,數(shù)據(jù)全部加載完畢后會(huì)隱藏加載更多
     * 如果返回false,數(shù)據(jù)全部加載完畢后會(huì)顯示getLoadEndViewId()布局
     */
    @Override public boolean isLoadEndGone() {
        return true;
    }

    @Override protected int getLoadingViewId() {
        return R.id.load_more_loading_view;
    }

    @Override protected int getLoadFailViewId() {
        return R.id.load_more_load_fail_view;
    }

    /**
     * isLoadEndGone()為true,可以返回0
     * isLoadEndGone()為false,不能返回0
     */
    @Override protected int getLoadEndViewId() {
        return 0;
    }
}
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="@dimen/dp_40">

    <LinearLayout
        android:id="@+id/load_more_loading_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:gravity="center"
        android:orientation="horizontal">

        <ProgressBar
            android:id="@+id/loading_progress"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            style="?android:attr/progressBarStyleSmall"
            android:layout_marginRight="@dimen/dp_4"
            android:indeterminateDrawable="@drawable/sample_footer_loading_progress"/>

        <TextView
            android:id="@+id/loading_text"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginLeft="@dimen/dp_4"
            android:text="@string/loading"
            android:textColor="#0dddb8"
            android:textSize="@dimen/sp_14"/>
    </LinearLayout>

    <FrameLayout
        android:id="@+id/load_more_load_fail_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:visibility="gone">


        <TextView
            android:id="@+id/tv_prompt"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center"
            android:textColor="#0dddb8"
            android:text="@string/load_failed"/>

    </FrameLayout>

</FrameLayout>

下拉加載(符合聊天軟件下拉歷史數(shù)據(jù)需求)


設(shè)置開(kāi)啟開(kāi)關(guān)

 mAdapter.setUpFetchEnable(true);

設(shè)置監(jiān)聽(tīng)

mAdapter.setUpFetchListener(new BaseQuickAdapter.UpFetchListener() {
            @Override
            public void onUpFetch() {
                startUpFetch();
            }
        });

private void startUpFetch() {
        count++;
        /**
         * set fetching on when start network request.
         */
        mAdapter.setUpFetching(true);
        /**
         * get data from internet.
         */
        mRecyclerView.postDelayed(new Runnable() {
            @Override
            public void run() {
                mAdapter.addData(0, genData());
                /**
                 * set fetching off when network request ends.
                 */
                mAdapter.setUpFetching(false);
                /**
                 * set fetch enable false when you don't need anymore.
                 */
                if (count > 5) {
                    mAdapter.setUpFetchEnable(false);
                }
            }
        }, 300);
    }

開(kāi)始加載的位置

mAdapter.setStartUpFetchPosition(2);

分組布局

實(shí)體類必須繼承SectionEntity

public class MySection extends SectionEntity<Video> {
    private boolean isMore;
    public MySection(boolean isHeader, String header) {
        super(isHeader, header);
    }

    public MySection(Video t) {
        super(t);
    }
}

adapter構(gòu)造需要傳入兩個(gè)布局id,第一個(gè)是item的,第二個(gè)是head的,在convert方法里面加載item數(shù)據(jù),在convertHead方法里面加載head數(shù)據(jù)

public class SectionAdapter extends BaseSectionQuickAdapter<MySection> {
     public SectionAdapter(int layoutResId, int sectionHeadResId, List data) {
        super(layoutResId, sectionHeadResId, data);
    }
    @Override
    protected void convert(BaseViewHolder helper, MySection item) {
        helper.setImageUrl(R.id.iv, (String) item.t);
    }
    @Override
    protected void convertHead(BaseViewHolder helper,final MySection item) {
        helper.setText(R.id.header, item.header);
       
        helper.setOnClickListener(R.id.more, new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Toast.makeText(context,item.header+"more..",Toast.LENGTH_LONG).show();
            }
        });
    }

多布局

實(shí)體類必須實(shí)現(xiàn)MultiItemEntity,在設(shè)置數(shù)據(jù)的時(shí)候,需要給每一個(gè)數(shù)據(jù)設(shè)置itemType

public class MultipleItem implements MultiItemEntity {
    public static final int TEXT = 1;
    public static final int IMG = 2;
    private int itemType;

    public MultipleItem(int itemType) {
        this.itemType = itemType;
    }

    @Override
    public int getItemType() {
        return itemType;
    }
}

在構(gòu)造里面addItemType綁定type和layout的關(guān)系

public class MultipleItemQuickAdapter extends BaseMultiItemQuickAdapter<MultipleItem, BaseViewHolder> {

    public MultipleItemQuickAdapter(List data) {
        super(data);
        addItemType(MultipleItem.TEXT, R.layout.text_view);
        addItemType(MultipleItem.IMG, R.layout.image_view);
    }

    @Override
    protected void convert(BaseViewHolder helper, MultipleItem item) {
        switch (helper.getItemViewType()) {
            case MultipleItem.TEXT:
                helper.setImageUrl(R.id.tv, item.getContent());
                break;
            case MultipleItem.IMG:
                helper.setImageUrl(R.id.iv, item.getContent());
                break;
        }
    }

}

注:如果想深入了解的原理可以查看BaseRecyclerAdapter之添加不同布局(優(yōu)化篇)

如果考慮到在GridLayoutManager復(fù)用item問(wèn)題可以配置:

  multipleItemAdapter.setSpanSizeLookup(new BaseQuickAdapter.SpanSizeLookup() {
            @Override
            public int getSpanSize(GridLayoutManager gridLayoutManager, int position) {
                return data.get(position).getSpanSize();
            }
        });

如果大家覺(jué)得這種多布局方式有點(diǎn)由于耦合了實(shí)體類,還有支持另外一種多布局方式具體可查看更便捷的多布局, 為 BaseQuickAdapter 設(shè)置代理.

如果使用多布局出現(xiàn)這個(gè)NotFoundException異常,有可能是addItemType()兩個(gè)參數(shù)寫反了。

設(shè)置空布局

// 沒(méi)有數(shù)據(jù)的時(shí)候默認(rèn)顯示該布局
mQuickAdapter.setEmptyView(getView());

如果用網(wǎng)格布局的話,設(shè)置空布局就不能給全屏,可以使用瀑布流布局。

添加拖拽、滑動(dòng)刪除

拖拽和滑動(dòng)刪除的回調(diào)方法

OnItemDragListener onItemDragListener = new OnItemDragListener() {
    @Override
    public void onItemDragStart(RecyclerView.ViewHolder viewHolder, int pos){}
    @Override
    public void onItemDragMoving(RecyclerView.ViewHolder source, int from, RecyclerView.ViewHolder target, int to) {}
    @Override
    public void onItemDragEnd(RecyclerView.ViewHolder viewHolder, int pos) {}
}

OnItemSwipeListener onItemSwipeListener = new OnItemSwipeListener() {
    @Override
    public void onItemSwipeStart(RecyclerView.ViewHolder viewHolder, int pos) {}
    @Override
    public void clearView(RecyclerView.ViewHolder viewHolder, int pos) {}
    @Override
    public void onItemSwiped(RecyclerView.ViewHolder viewHolder, int pos) {}
};

adapter需要繼承BaseItemDraggableAdapter

public class ItemDragAdapter extends BaseItemDraggableAdapter<String, BaseViewHolder> {
    public ItemDragAdapter(List data) {
        super(R.layout.item_draggable_view, data);
    }

    @Override
    protected void convert(BaseViewHolder helper, String item) {
        helper.setText(R.id.tv, item);
    }
}

Activity使用代碼

mAdapter = new ItemDragAdapter(mData);

ItemDragAndSwipeCallback itemDragAndSwipeCallback = new ItemDragAndSwipeCallback(mAdapter);
ItemTouchHelper itemTouchHelper = new ItemTouchHelper(itemDragAndSwipeCallback);
itemTouchHelper.attachToRecyclerView(mRecyclerView);

// 開(kāi)啟拖拽
mAdapter.enableDragItem(itemTouchHelper, R.id.textView, true);
mAdapter.setOnItemDragListener(onItemDragListener);

// 開(kāi)啟滑動(dòng)刪除
mAdapter.enableSwipeItem();
mAdapter.setOnItemSwipeListener(onItemSwipeListener);

默認(rèn)不支持多個(gè)不同的 ViewType 之間進(jìn)行拖拽,如果開(kāi)發(fā)者有所需求:

重寫ItemDragAndSwipeCallback里的onMove()方法,return true即可

樹(shù)形列表

例子:三級(jí)菜單

// if you don't want to extent a class, you can also use the interface IExpandable.
// AbstractExpandableItem is just a helper class.
public class Level0Item extends AbstractExpandableItem<Level1Item> {...}
public class Level1Item extends AbstractExpandableItem<Person> {...}
public class Person {...}

adapter需要繼承BaseMultiItemQuickAdapter

public class ExpandableItemAdapter extends BaseMultiItemQuickAdapter<MultiItemEntity, BaseViewHolder> { 
    public ExpandableItemAdapter(List<MultiItemEntity> data) {    
        super(data);
        addItemType(TYPE_LEVEL_0, R.layout.item_expandable_lv0);   
        addItemType(TYPE_LEVEL_1, R.layout.item_expandable_lv1);    
        addItemType(TYPE_PERSON, R.layout.item_text_view);
    }
    @Override
    protected void convert(final BaseViewHolder holder, final MultiItemEntity item) {
        switch (holder.getItemViewType()) {
        case TYPE_LEVEL_0:
            ....
            //set view content
           holder.itemView.setOnClickListener(new View.OnClickListener() {
               @Override
               public void onClick(View v) {
                   int pos = holder.getAdapterPosition();
                   if (lv0.isExpanded()) { 
                       collapse(pos);
                   } else {
                       expand(pos);
                   }
           }});
           break;
        case TYPE_LEVEL_1:
           // similar with level 0
           break;
        case TYPE_PERSON:
           //just set the content
           break;
    }
}

開(kāi)啟所有菜單:

adapter.expandAll();

刪除某一個(gè)item(添加和修改的思路是一樣的)

// 獲取當(dāng)前父級(jí)位置
 int cp = getParentPosition(person);
// 通過(guò)父級(jí)位置找到當(dāng)前l(fā)ist,刪除指定下級(jí)
 ((Level1Item)getData().get(cp)).removeSubItem(person);
// 列表層刪除相關(guān)位置的數(shù)據(jù)
 getData().remove(holder.getLayoutPosition());
// 更新視圖
 notifyDataSetChanged();

自定義ViewHolder

需要繼承BaseViewHolder

 public class MovieViewHolder extends BaseViewHolder 

然后修改adapter的第二個(gè)泛型為自定義的ViewHolder

public class DataBindingUseAdapter extends BaseQuickAdapter<Movie, DataBindingUseAdapter.MovieViewHolder>

注意:需要單獨(dú)建一個(gè)外部類繼承BaseViewHolder,否則部分機(jī)型會(huì)出現(xiàn)ClassCastException,如果是內(nèi)部類的構(gòu)造方法要是public,定義的那個(gè)類也最好是public。

混淆

-keep class com.chad.library.adapter.** {
*;
}
-keep public class * extends com.chad.library.adapter.base.BaseQuickAdapter
-keep public class * extends com.chad.library.adapter.base.BaseViewHolder
-keepclassmembers  class **$** extends com.chad.library.adapter.base.BaseViewHolder {
     <init>(...);
}

擴(kuò)展框架

由于adapter本身能力有限,我們又不想耦合view層所以有些需求是現(xiàn)實(shí)不了,于是合作了一些優(yōu)秀開(kāi)源庫(kù),為開(kāi)發(fā)者提供更多可能性。以下擴(kuò)展框架都是有結(jié)合BRVAH的demo。

本文章由于持續(xù)更新,建議點(diǎn)贊收藏,便于查看。

官方網(wǎng)站:www.recyclerview.org
Demo下載地址:http://fir.im/s91g

如果有問(wèn)題:提問(wèn),請(qǐng)先看這個(gè)!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容