RecyclerView高速通用適配Adapter


RecyclerView Adapter

  1. 為RecyclerView提供更簡單的適配器實現方式,不斷更新完好中。

  2. Demo視頻演示

  3. GitHub地址

  4. 博客

使用

  • 類庫還在開發中。臨時沒有公布到Jcenter,所以須要在yourProject.gradle文件里加入例如以下代碼進行依賴
    allprojects { repositories { maven { url 'https://dl.bintray.com/chendongmarch/maven' }
        }
    }
  • yourApp.gradle文件里加入依賴
    compile 'com.march.lib-adapter:lib-adapter:1.0.0'

BaseViewHolder 的使用

  • 通用ViewHolder,內部使用SparseArray實現View的緩存。
//BaseViewHolder

//獲取控件
public <T extends View> T getView(int resId)
public <T extends View> T getView(String resId)
//設置可見
public RvViewHolder setVisibility(int resId, int v)
//文字
public RvViewHolder setText(int resId, String txt)
//圖片
public RvViewHolder setImg(int resId, int imgResId)
//監聽
public RvViewHolder setClickLis(int resId, View.OnClickListener listener)

通用適配器

單類型數據適配

  • SimpleRvAdapter
//一個簡單的實現,實體類不須要再去實現RvQuickInterface接口
SimpleRvAdapter simpleAdapter =
new SimpleRvAdapter<Demo>(self, demos, R.layout.rvquick_item_a) {
            @Override
            public void onBindView(RvViewHolder holder, Demo data, int pos) {
                holder.setText(R.id.item_a_tv, data.title);
            }
        };

多類型數據適配

  • TypeRvAdapter

    1. 多類型數據適配時須要接受ITypeAdapterModel(接口)類型的的數據,因此進行多類型數據適配時,你的Model須要實現ITypeAdapterModel告知Adapter數據的type

    2. addType(int type,int res)方法用來給每種類型的數據加入不同的布局文件,達到多類型適配的目的。

// Demo類必須實現 ITypeAdapterModel 接口
TypeRvAdapter<Demo> typeAdapter =
new TypeRvAdapter<Demo>(context, data) {
            @Override
            public void onBindView(RvViewHolder holder, Demo data, int pos, int type) {
                //依據類型綁定數據
                switch (type) {
                    case Demo.CODE_DETAIL:
                        holder.setText(R.id.item_quickadapter_type_title, data.getmDemoTitle()).setText(R.id.item_quickadapter_desc, data.getmDescStr());
                        break;
                    case Demo.JUST_TEST:
                        holder.setText(R.id.item_quickadapter_title, data.getmDemoTitle());
                        break;
                }
            }

        };
typeAdapter.addType(Demo.CODE_DETAIL, R.layout.item_layout_a)
           .addType(Demo.JUST_TEST, R.layout.item_layout_b);

九宮格模式適配

  • SectionRvAdapter

    1. 每一個Header以下由多個item。相似微信九宮格照片展示,SectionRvAdapter實際上是多類型適配(TypeRvAdapter)的一種特殊形式,內置了SectionHeader類型的數據,用來更簡單的實現九宮格模式的數據適配,由於多類型數據適配的特點他都能夠使用,也就是說你能夠定義多種類型的數據展示。

    2. 作為ItemHeader的數據類型須要繼承AbsSectionHeader(抽象類)

class ItemHeader extends AbsSectionHeader {
        String itemHeaderTitle;
}
  1. 作為每一個Section內容的數據類型,假設他是單類型的不須要做其它操作。假設有多種類型的內容須要實現ITypeAdapterModel,具體參照多類型數據適配多類型數據適配
class Content {
         int contentIndex
        String contentTitle;
}

使用 ISectionRule 配置數據

  1. ISectionRule接口,進行九宮格模式適配使用 ISectionRule 配置數據時,須要加入ISectionRule,這是一種規則。adapter會依據你提供的規則自己主動生成Header

  2. 提供了兩種構造方法

// 直接配置 item header 和 content 的 layout 資源
public SectionRvAdapter(Context context,List<ID> originDatas,
                        int headerLayoutId, int contentLayoutId)
// 僅僅加入 header 的 layout 資源。content的資源能夠使用addType方法加入                        
public SectionRvAdapter(Context context, List<ID> originDatas,
                        int headerLayoutId)
// ItemHeader表示header的數據類型,Content表示內部數據的數據類型
// 初始化,加入header 和 content的布局文件
adapter = new SectionRvAdapter<ItemHeader, Content>(
                this,
                contents,
                R.layout.item_header_header,
                R.layout.item_header_content) {
            @Override
            protected void onBindItemHeader(BaseViewHolder holder, ItemHeader data, int pos, int type) {
                holder.setText(R.id.info1, data.getItemHeaderTitle());
            }

            @Override
            protected void onBindContent(BaseViewHolder holder, Content data, int pos, int type) {
                holder.setText(R.id.tv, String.valueOf(data.contentIndex));
            }
        };

         // 加入ISectionRule
        adapter.addItemHeaderRule(new ISectionRule<ItemHeader, Content>() {
            @Override
            public ItemHeader buildItemHeader(int currentPos, Content preData, Content currentData, Content nextData) {
                    // 生成header數據
                return new ItemHeader("create new header " + currentData.contentIndex);
            }

            @Override
            public boolean isNeedItemHeader(int currentPos, Content preData, Content currentData, Content nextData) {
                    // 什么時候創建header(當是第一個數據或者index是7的倍數時,插入一個header)
                return currentPos == 0 || currentData.contentIndex % 7 == 1;
            }
        });
mRv.setAdapter(adapter);

使用 HashMap 配置數據

  1. 一個 ItemHeader 下有多個 Content。相似Map<ItemHeader,Content>的數據結構,能夠選擇在外面構造好數據來進行數據適配

  2. HashMap是無序的,為了保證數據的有序性,使用LinkedHashMap

  3. 相同的也提供了兩種構造方法

// 直接配置 item header 和 content 的 layout 資源
public SectionRvAdapter(Context context,
                            LinkedHashMap<IH, List<ID>> originDatas,
                            int headerLayoutId, int contentLayoutId)

// 僅僅加入 header 的 layout 資源,content的資源能夠使用addType方法加入 
public SectionRvAdapter(Context context,
                            LinkedHashMap<IH, List<ID>> originDatas,
                            int headerLayoutId) 
final LinkedHashMap<ItemHeader, List<Content>> map = new LinkedHashMap<>();
adapter = new SectionRvAdapter<ItemHeader, Content>(this, map,
                R.layout.item_header_header,
                R.layout.item_header_content) {
            @Override
            protected void onBindItemHeader(BaseViewHolder holder, ItemHeader data, int pos, int type) {
                holder.setText(R.id.info1, data.getItemHeaderTitle());
            }

            @Override
            protected void onBindContent(BaseViewHolder holder, Content data, int pos, int type) {
                TextView tv = (TextView) holder.getView(R.id.tv);
            }
        };

監聽事件

支持單擊、雙擊和長按事件

三種事件

public interface OnItemListener<D> {
    // 單擊事件
    void onClick(int pos, BaseViewHolder holder, D data);
    // 長按事件
    void onLongPress(int pos, BaseViewHolder holder, D data);
    // 雙擊事件
    void onDoubleClick(int pos, BaseViewHolder holder, D data);
}

實現須要的事件

抽象類的實現,能夠選擇性的實現須要的方法

public abstract class SimpleItemListener<D> implements OnItemListener<D> {

    @Override
    public void onClick(int pos, BaseViewHolder holder, D data) {

    }

    @Override
    public void onLongPress(int pos, BaseViewHolder holder, D data) {

    }

    @Override
    public void onDoubleClick(int pos, BaseViewHolder holder, D data) {

    }
}

            adapter.setItemListener(new SimpleItemListener <GuideData>() {
            @Override
            public void onClick(int pos, BaseViewHolder holder, GuideData data) {
                 Toast.makeText(mContext, "單擊事件", Toast.LENGTH_SHORT).show();
            }

            @Override
            public void onLongPress(int pos, BaseViewHolder holder, GuideData data) {
                Toast.makeText(mContext, "長按事件", Toast.LENGTH_SHORT).show();
            }

            @Override
            public void onDoubleClick(int pos, BaseViewHolder holder, GuideData data) {
                Toast.makeText(mContext,"雙擊事件", Toast.LENGTH_SHORT).show();
            }
        });

SectionRvAdapter 事件

adapter.setItemListener(new SimpleItemListener<ItemModel>() {
            @Override
            public void onClick(int pos, BaseViewHolder holder, ItemModel data) {
                        // 當是Content數據類型
                if (data.getRvType() == AbsAdapter.TYPE_ITEM_DEFAULT) {
                    Content content = (Content) data.get();
                    Toast.makeText(SectionAdapterTest.this, content.contentTitle, Toast.LENGTH_SHORT).show();
                }else{
                        // 當是ItemHeader數據類型
                }
            }
        });

數據更新

為了簡化數據更新的方法。內置了數據更新的部分方法

內置更新方法

// 插入一條數據
public void insert(int pos, D data) 
// 更新數據,isUpdate為false時僅僅會加入數據不會更新顯示
public void notifyDataSetChanged(List<D> data, boolean isUpdate)

分頁更新方法

// 簡化分頁載入的更新。調用該方法實現增量更新,不會所有刷新。isAllData為true時表示data是所有數據。為false時表示是追加的數據
public void appendTailRangeData(List<D> data, boolean isAllData)

SectionRvAdapter 追加更新

// SectionRvAdapter比較特別,須要使用單獨的更新方法

// 使用SectionRule配置數據時,使用此方法更新
public void updateDataAndItemHeader(List<ID> data)
// 使用Map配置數據時,使用此方法更新
public void updateDataAndItemHeader(Map<IH, List<ID>> map)
// 分頁載入更新數據時調用,僅支持使用SectionRule配置數據
public void appendSectionTailRangeData(List<ID> data)

Module

使用Module配置附加功能,眼下有HFModule(加入Header和Footer)、LoadMoreModule(預載入很多其它)

  • HFModule
// 生成和加入module
HFModule hfModule = new HFModule(mContext,
                R.layout.header_footer_headerly,
                R.layout.header_footer_footerly, mRv);
adapter.addHFModule(hfModule);
// 更改Header 和 Footer的數據,相似數據的配置,你能夠在實現的方法里綁定數據和監聽事件
adapter = new SimpleRvAdapter<HFModel>(mContext, hfModels, R.layout.header_footer_item) {
            @Override
            public void onBindHeader(BaseViewHolder header) {
                super.onBindHeader(header);
            }

            @Override
            public void onBindFooter(BaseViewHolder footer) {
                super.onBindFooter(footer);
            }
        };
// 當僅僅想加入Header或Footer時,使用常亮HFModule.NO_RES表示沒有資源
HFModule hfModule = new HFModule(mContext,HFModule.NO_RES,
                HFModule.NO_RES, mRv);

// 隱藏Header 和 Footer
public void setFooterEnable(boolean footerEnable)
public void setHeaderEnable(boolean headerEnable)

預載入很多其它

  • LoadMoreModule

new LoadMoreModule(int preLoadNum, OnLoadMoreListener lis),preLoadNum表示提前幾個Item進行預載入,preLoadNum越大預載入的越提前
載入數據完畢之后須要調用mLoadMoreModule.finishLoad();結束本次載入,保證下次載入能夠生效

        // 觸發之后1500秒后載入數據
        LoadMoreModule loadMoreM = new LoadMoreModule(4, new OnLoadMoreListener() {
            @Override
            public void onLoadMore(final LoadMoreModule mLoadMoreModule) {
                new Handler().postDelayed(new Runnable() {
                    @Override
                    public void run() {
                        List<LoadMoreModel> tempData = new ArrayList<LoadMoreModel>();
                        for (int i = 0; i < 9; i++) {
                            tempData.add(new LoadMoreModel("new is " + i));
                        }
                        adapter.appendTailRangeData(tempData, false);
                        mLoadMoreModule.finishLoad();
                    }
                }, 1500);
            }
        });
        adapter.addLoadMoreModule(loadMoreM);

其它

adapterId 區分

為了區分不同的適配器,生成了adapterId,用來檢測當前RecyclerView使用的是不是這個adapter

public boolean isThisAdapter(RecyclerView rv)

Sample


//內部類實現
quickAdapter = new TypeRvAdapter<Demo>(self, demos) {
            @Override
            public void onBindView(RvViewHolder holder, Demo data, int pos, int type) {
               // 給控件綁定數據,必須實現
            }

            @Override
            public void onBindHeader(RvViewHolder header) {
               //給Header綁定數據和事件,不須要能夠不實現
            }

            @Override
            public void onBindFooter(RvViewHolder footer) {
               //給footer綁定數據和事件,不須要能夠不實現
            }
        };





//繼承實現
public class MyAdapter extends TypeRvAdapter<Demo> {

    public MyAdapter(Context context, List<Demo> data) {
        super(context, data);
    }

    @Override
    public void onBindView(RvViewHolder holder, Demo data, int pos, int type) {
       // 給控件綁定數據,必須實現
    }

    @Override
    public void onBindHeader(RvViewHolder header) {
       //給Header綁定數據和事件,不須要能夠不實現
    }

    @Override
    public void onBindFooter(RvViewHolder footer) {
       //給footer綁定數據和事件,不須要能夠不實現
    }
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM