BRAVH源碼模擬

BRAVH是一個(gè)recyclerView的adapter葬燎,能夠快速適配多種類型adapter谱净,可定制,用的人挺多裕寨,下面我們就來分析分析他的源碼,模擬來寫一個(gè)我們的adapter驾窟。

我們將recyclerView的adapter與自定義viewholder聯(lián)系在一起绅络,使用了BaseQuickAdapter<T, K extends BaseViewHolder>來作為recycler.adapter

先看BRAVH的BaseViewHolder類

BaseViewHolder extends RecyclerView.ViewHolder

繼承自ViewHolder,里面setXXX方法全是由itemview里面的view調(diào)用方法實(shí)現(xiàn)
存放了一個(gè)SparseArray<View> views成員變量用來初始化或者第一次遍歷存放引用衷恭,添加快捷操作随珠,省去下一次findview的時(shí)間

接下來看BaseQuickAdapter類

BaseQuickAdapter<T, K extends BaseViewHolder> extends RecyclerView.Adapter<K>

將K泛型傳入給RecyclerView.Adapter作為viewholder
T泛型分析:
傳入的數(shù)據(jù)集List<T>的類型,用來綁定數(shù)據(jù)

自定義Adapter,Viewholder

我們也來模擬一個(gè)adapter類型,使用自定義繼承viewHolder的MyViewHolder作為Viewholder

public class BackQuickAdapter<I,VH extends MyViewHolder> extends RecyclerView.Adapter<VH> {

    private List<String> datas;

    public BackQuickAdapter(List<String> datas) {
        this.datas = datas;
    }

    @Override
    public VH onCreateViewHolder(ViewGroup parent, int viewType) {
        View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.recycler_list,parent,false);
        //實(shí)例化VH對(duì)象
        return createViewHolder(view);
    }

    @Override
    public void onBindViewHolder(VH holder, int position) {
        View contentView = holder.itemView;
        ((TextView)contentView.findViewById(R.id.recycler_list_txt)).setText(datas.get(position));
        //do something about contentView
    }

    @Override
    public int getItemCount() {
        return datas == null ? 0 : datas.size();
    }

}

這樣我們就有了一個(gè)adapter显沈,里面的Viewholder由外部傳進(jìn)來,我們可以繼承該Viewholder自己做快捷操作遂唧,讓外部繼承實(shí)現(xiàn)MyViewholder邏輯盖彭,同BaseViewHolder,他也只是對(duì)itemview引用設(shè)置子View參數(shù)隧熙,這部分基本忽略贞盯。我們看onCreateViewHolder->VH createViewHolder(View view)這個(gè)方法躏敢,這是一個(gè)泛型類的實(shí)例化讥脐,這個(gè)直接上代碼見git旬渠。

給itemView添加加載動(dòng)畫

onViewAttachedToWindow(VH holder)方法:
每次Viewholder添加到window的時(shí)候contentView開始動(dòng)畫可以制作item加載效果
想要控制只讓itemView進(jìn)行一次動(dòng)畫,BRAVH里面設(shè)置了一個(gè)標(biāo)志位更哄,我們也寫一個(gè)AnimOnce來做這個(gè)標(biāo)志位成翩,每次加載的時(shí)候得到viewholder的位置,并與上一次的加載過的位置比較术羔,如果小级历,代表當(dāng)前位置的contentview是新的,需要開啟動(dòng)畫,否則如果AnimOnce只要一次粤策,不開啟動(dòng)畫叮盘,因?yàn)閯?dòng)畫已經(jīng)之前被加載過,我們可以這樣實(shí)現(xiàn):

/**
 * 是否只需要一次item加載動(dòng)畫
 */
private boolean AnimOnce = true;
/**
 * 最新加載過動(dòng)畫的item的位置柔吼,用于比較下一次item的位置判斷是否要加載
 */
private int vaildPos = 0;
@Override
public void onViewAttachedToWindow(VH holder) {
    int currentPos = holder.getAdapterPosition();
    if(AnimOnce)
        if(currentPos > vaildPos){
            animateView(holder.itemView);
            vaildPos = currentPos;
        }
    else{
            animateView(holder.itemView);
        }
    super.onViewAttachedToWindow(holder);
}
private void animateView(View root){
    root.setAlpha(0.3f);
    root.animate().alpha(1).setDuration(2500).start();
}
public void setAnimOnce(boolean animOnce) {
    AnimOnce = animOnce;
}

這樣萍膛,就能添加我們的itemview動(dòng)畫,如果需要外部定制嚷堡,我們可以修改我們的animateView(View root)方法蝗罗,給里面添加一個(gè)animation動(dòng)畫,并且提供外部接口蝌戒,比如:

private Animation animation = null;
public void setItemAnimation(Animation animation) {
    this.animation = animation;
}

private void animateView(View root){
    if(null != animation)
    {
        root.startAnimation(animation);
    }
}

關(guān)于動(dòng)畫串塑,可以使用animator或者animation都可以的北苟,只要定制animateView方法

添加頭部尾部空數(shù)據(jù)的布局

我們看BRAVH如何實(shí)現(xiàn)妆档,

  1. 添加header,footer,loading的view
  2. GetItemCount需要返回的數(shù)據(jù)量為headercount + datas.size + footercount + loadingcount
  3. GetItemType如果position < headercount须板,返回頭布局類型甜奄,得到普通布局的normal_position = position - headercount如果normal_position < datas.size [List數(shù)據(jù)集],返回普通列表類型,否則代表有尾布局footer

下面我們也來模擬一個(gè)頭部尾部布局~
寫一個(gè)方法來添加頭部尾部視圖

private int headerLayout;
private int footerLayout;
private boolean hasHeader = false;
private boolean hasFooter = false;
//added first before call setAdapter
public void addHeaderView(@LayoutRes int headerLayout){
    this.headerLayout = headerLayout;
    hasHeader = true;
}
//added first before call setAdapter
public void addFooterView(@LayoutRes int footerLayout){
    this.footerLayout = footerLayout;
    hasFooter = true;
}

GetItemType返回對(duì)應(yīng)Type

@Override
public int getItemCount() {
    return datas == null ? 0 : datas.size() + (hasFooter ? 1 : 0) + (hasHeader ? 1 : 0);
}
private final static int ITEM_TYPE_HEADER = -1;
private final static int ITEM_TYPE_NORMAL = 0;
private final static int ITEM_TYPE_FOOTER = 1;
@Override
public int getItemViewType(int position) {
    int datasize = (datas == null ? 0 : datas.size());
    int headerCount = hasHeader ? 1 : 0;
    if(position < headerCount)
        return ITEM_TYPE_HEADER;
    int realIndex = position - headerCount;
    if(realIndex < datasize){
        return ITEM_TYPE_NORMAL;
    }
    else{
        return ITEM_TYPE_FOOTER;
    }
}

根據(jù)對(duì)于Type構(gòu)造Viewholder

@Override
public VH onCreateViewHolder(ViewGroup parent, int viewType) {
    View view = null;
    switch (viewType)
    {
        case ITEM_TYPE_HEADER:
            view = LayoutInflater.from(parent.getContext()).inflate(headerLayout, parent, false);
            break;
        case ITEM_TYPE_FOOTER:
            view = LayoutInflater.from(parent.getContext()).inflate(footerLayout, parent, false);
            break;
        default:
            view = LayoutInflater.from(parent.getContext()).inflate(R.layout.recycler_list, parent, false);
    }
    //實(shí)例化VH對(duì)象
    return createViewHolder(view);
}

根據(jù)position位置來綁定viewholder數(shù)據(jù)

@Override
public void onBindViewHolder(VH holder, int position) {
    if(position < (hasHeader ? 1 : 0))
    {
        // this is header view
        return ;
    }
    int realDataPos = adjustPositionByType(position);
    if(realDataPos < datas.size())
    {
        View contentView = holder.itemView;
        ((TextView)contentView.findViewById(R.id.recycler_list_txt)).setText(datas.get(realDataPos));
    }
    else{
        //this is footer View
    }
}

這樣我們的頭部尾部布局就添加好了勺卢,添加loading布局與空布局也是一個(gè)道理,只是多加載了一種類型而已

加載更多的實(shí)現(xiàn)

這是在OnBindViewHolder->position判斷位置
如果position已經(jīng)在最后的位置唐全,那么觸發(fā)加載更多
下面我們可以寫一個(gè)加載更多的方法:

private void autoLoadMore(int position) {
    if(position == getItemCount() -1)
    {
        Log.i("position","current end is "+String.valueOf(position));
        //trigger loading more
    }
}
@Override
public int getItemCount() {
    return datas == null ? 0 : datas.size() + (hasFooter ? 1 : 0) + (hasHeader ? 1 : 0);
}

實(shí)現(xiàn)拖拽延届,滑動(dòng)刪除

BRAVH是怎么實(shí)現(xiàn)呢?官方這樣使用:

ItemDragAndSwipeCallback itemDragAndSwipeCallback = new ItemDragAndSwipeCallback(mAdapter);
ItemTouchHelper itemTouchHelper = new ItemTouchHelper(itemDragAndSwipeCallback);
itemTouchHelper.attachToRecyclerView(mRecyclerView);
// 開啟拖拽
mAdapter.enableDragItem(itemTouchHelper, R.id.textView, true);
mAdapter.setOnItemDragListener(onItemDragListener);
// 開啟滑動(dòng)刪除
mAdapter.enableSwipeItem();
mAdapter.setOnItemSwipeListener(onItemSwipeListener);

我們可以看到使用的類是ItemDragAndSwipeCallback 希停,這里面需要傳入adapter需要BaseItemDraggableAdapter類型阿弃,我們進(jìn)入ItemDragAndSwipeCallback 發(fā)現(xiàn)其實(shí)只是BaseItemDraggableAdapter回調(diào)用,其實(shí)本身并沒有用到任何BaseItemDraggableAdapter屬性呵恢。所以可以做出一個(gè)提取的過程声离,把傳入類型BaseItemDraggableAdapter修改成interface,只要RecyclerAdapter實(shí)現(xiàn)這個(gè)接口就可以了垃它,這樣不必非要傳入BaseItemDraggableAdapter類型。


這部分也可以直接用原生ItemTouchHelper陕习,復(fù)寫onMove實(shí)現(xiàn)item交換嫁审,onSwiped實(shí)現(xiàn)Item刪除
我們開始寫交換邏輯:

  1. 首先剔除header視圖的位置獲得在datas數(shù)據(jù)集中的位置realpos
  2. 交換數(shù)據(jù)集中的realpos位置數(shù)據(jù)
  3. Notifydatachanged
    或許我們可以這樣實(shí)現(xiàn)
@Override
public void onItemDragMoving(RecyclerView.ViewHolder source, RecyclerView.ViewHolder target) {
    //change item position
    int from = getViewHolderPosition(source);
    int to = getViewHolderPosition(target);
    if (inRange(from) && inRange(to)) {
        if (from < to) {
            for (int i = from; i < to; i++) {
                Collections.swap(datas, i, i + 1);
            }
        } else {
            for (int i = from; i > to; i--) {
                Collections.swap(datas, i, i - 1);
            }
        }
        notifyItemMoved(source.getAdapterPosition(), target.getAdapterPosition());
    }
}
public int getViewHolderPosition(RecyclerView.ViewHolder viewHolder) {
    return viewHolder.getAdapterPosition() - (hasHeader ? 1 : 0);
}
private boolean inRange(int position) {
    return position >= 0 && position < datas.size();
}

下面我們實(shí)現(xiàn)刪除邏輯:

  1. 首先剔除header視圖的位置獲得在datas數(shù)據(jù)集中的位置realpos
  2. 刪除數(shù)據(jù)集中的realpos位置數(shù)據(jù)
  3. NotifyItemRemoved
@Override
public void onItemSwiped(RecyclerView.ViewHolder viewHolder) {
    //notify item removed
    int position = getViewHolderPosition(viewHolder);
    if(position >= 0 && position < datas.size()) {
        datas.remove(position);
        notifyItemRemoved(getPositionInSets(position));
    }
}
public int getPositionInSets(int position) {
    return position + (hasHeader ? 1 : 0);
}

自定義使用不同的Item類型
現(xiàn)在默認(rèn)item類型有header眷蜓,footer白魂,loading背传,empty梳星,default。如果想要自定義類型痒蓬,那么我們可以修改自定義的adapter,在getItemType返回default類型的時(shí)候双揪,使用抽象方法讓子類實(shí)現(xiàn)动羽,修改adapter為抽象類,這將影響:

  1. getItemtype 使用抽象方法getDefItemViewType(int realDataPos)
  2. oncreateViewholder 返回的View需要根據(jù)自定義itemtype實(shí)現(xiàn)自定義view渔期,所以暴露抽象方法onCreateDefViewHolder(ViewGroup parent, int viewType)
  3. onBindViewHolder 綁定數(shù)據(jù)時(shí)需要根據(jù)自定義的ViewHolder來自定視圖數(shù)據(jù)的綁定运吓,所以暴露抽象方法onBindDefViewHolder(VH holder, int realDataPos)

這樣我們便能夠自定義itemType


getItemtype 使用抽象方法getDefItemViewType(int realDataPos)

public int getItemViewType(int position) {
    int datasize = (datas == null ? 0 : datas.size());
    int headerCount = hasHeader ? 1 : 0;
    if(position < headerCount)
        return ITEM_TYPE_HEADER;
    int realIndex = position - headerCount;
    if(realIndex < datasize){
        return getDefItemViewType(realIndex);
    }
    else{
        return ITEM_TYPE_FOOTER;
    }
}
//multi item must be override
protected int getDefItemViewType(int realDataPos) {
    //datas position item Type
    return ITEM_TYPE_NORMAL;
}

暴露抽象方法onCreateDefViewHolder(ViewGroup parent, int viewType)

public VH onCreateViewHolder(ViewGroup parent, int viewType) {
    View view = null;
    switch (viewType)
    {
        case ITEM_TYPE_HEADER:
            view = LayoutInflater.from(parent.getContext()).inflate(headerLayout, parent, false);
            break;
        case ITEM_TYPE_FOOTER:
            view = LayoutInflater.from(parent.getContext()).inflate(footerLayout, parent, false);
            break;
        default:
            view = onCreateDefViewHolder(parent,viewType);
    }
    //實(shí)例化VH對(duì)象
    return createViewHolder(view);
}

//be override
abstract View onCreateDefViewHolder(ViewGroup parent, int viewType);

回顧的時(shí)候發(fā)現(xiàn)還是返回VH類型的Viewholder容易定制渴邦,這樣自定義實(shí)現(xiàn)就不需要泛型實(shí)例化方法
abstract VH onCreateDefViewHolder(ViewGroup parent, int viewType);


暴露抽象方法onBindDefViewHolder(VH holder, int realDataPos)

public void onBindViewHolder(VH holder, int position) {
    autoLoadMore(position);

    if(position < (hasHeader ? 1 : 0))
    {
        // this is header view
        return ;
    }
    int realDataPos = adjustPositionByType(position);
    if(realDataPos < datas.size())
    {
        onBindDefViewHolder(holder,realDataPos);
    }
    else{
        //this is footer View
    }
}
//be override
abstract void onBindDefViewHolder(VH holder, int realDataPos);

我們的ItemType是由傳入的數(shù)據(jù)類型決定的,可以定義一個(gè)接口拘哨,讓傳入的數(shù)據(jù)類型實(shí)現(xiàn)該接口并且實(shí)現(xiàn)getItemType

public interface ItemType {
    int getItemType();
}
public class MultiAdapter<T extends ItemType,VH extends MyViewHolder> extends BackQuickAdapter<T,VH>{

    public MultiAdapter(List<T> datas) {
        super(datas);
    }

    @Override
    View onCreateDefViewHolder(ViewGroup parent, int viewType) {
        return LayoutInflater.from(parent.getContext()).inflate(R.layout.recycler_list, parent, false);
    }
    @Override
void onBindDefViewHolder(VH holder, int realDataPos) {
    View contentView = holder.itemView;
    String args = "自定義數(shù)據(jù)類型:"+String.valueOf(datas.get(realDataPos).getItemType());
    ((TextView)contentView.findViewById(R.id.recycler_list_txt)).setText(args);
}
    @Override
    protected int getDefItemViewType(int realDataPos) {
        return datas.get(realDataPos).getItemType();
    }
}

這樣就可以在外部自定義數(shù)據(jù)類型了

添加分組

首先我們看BRAVH怎么介紹

  1. 實(shí)體數(shù)據(jù)集類型要繼承SectionEntity

Stop,我們到這邊似乎不必要去看他怎么實(shí)現(xiàn)了谋梭,我猜原理應(yīng)該和上面添加自定義類型是一樣的,上面更加廣泛倦青,所以這里我們只有2種類型而已瓮床,一種分組頭類型。一種分組內(nèi)容類型姨夹。
我們開始編寫代碼試試:

  1. 寫一個(gè)數(shù)據(jù)集類型實(shí)現(xiàn)ItemType接口
  2. 數(shù)據(jù)集返回2種類型纤垂,第一種是分組頭類型假定(GroupHeader),第二種是一種分組內(nèi)容類型(GroupContent)
  3. 編寫我們的Adapter傳入?yún)?shù)類型為1的類型

我們先寫一個(gè)數(shù)據(jù)集類型實(shí)現(xiàn)ItemType接口

public class GroupEntity implements ItemType{
    public final static int GROUPHEADER = 0X11;
    public final static int GROUPCONTENT = 0X12;

    private boolean isHeader = false;
    private String values;

    public GroupEntity(boolean isHeader, String values) {
        this.isHeader = isHeader;
        this.values = values;
    }
    @Override
    public int getItemType() {
        return isHeader ? GROUPHEADER : GROUPCONTENT;
    }
}

這樣添加分組就是2種自定義數(shù)據(jù)類型而已,我們可以寫一個(gè)實(shí)體類磷账,返回2種類型峭沦,使用MultiAdapter適配,實(shí)現(xiàn)方法:

  • onCreateDefViewHolder:根據(jù)viewType來inflate不同的layout的子view
  • onBindDefViewHolder:根據(jù)Viewholder的VH holder, int position來綁定itemview與數(shù)據(jù)

分組的伸縮欄

既然要實(shí)現(xiàn)分組逃糟,我的思路是這樣的

  1. 是否需要提供不同的itemtype吼鱼,然后根據(jù)不同itemtype提供不同級(jí)別的子View,這樣視圖倒是沒有問題了绰咽。
  2. 下面需要思考的是數(shù)據(jù)菇肃,如果想要添加到列表的數(shù)據(jù)集中,之前我們定義的是T類型取募,那么不同級(jí)別也是要是T類型的才能加入到列表的數(shù)據(jù)集中
  3. 然后插入notifyitemInserted琐谤,刪除notifyitemremoved這樣就沒問題了.

可是設(shè)計(jì)主實(shí)體類或許有些麻煩了,要求里面有個(gè)子數(shù)據(jù)集類型是實(shí)體類類型的:
我們先定義接口

public interface Expandable<E> extends ItemType{
    List<E> subItems();
    boolean isExpandable();
    void setExpand(boolean expand);
    boolean isExpand();
}

這個(gè)接口要求子數(shù)據(jù)級(jí)玩敏,是否可以擴(kuò)展

然后定義數(shù)據(jù)類型

public class ExpandEntity implements Expandable<ExpandEntity>{

    public final static int SUB1 = 0x111;
    public final static int SUB2 = 0x112;
//    public final static int SUB3 = 0x113;

    private int itemType;
    private List<ExpandEntity> subDatas;
    private String values;

    public ExpandEntity(int itemType, List<ExpandEntity> subDatas,String values) {
        this.itemType = itemType;
        this.subDatas = subDatas;
        this.values = values;
    }

    public String getValues() {
        return values;
    }

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

    @Override
    public List<ExpandEntity> subItems() {
        return subDatas;
    }

    @Override
    public boolean isExpandable() {
        return subDatas != null && subDatas.size() > 0;
    }

    boolean isExpand = false;
    @Override
    public void setExpand(boolean expand) {
        isExpand = expand;
    }

    @Override
    public boolean isExpand() {
        return isExpand;
    }
}

這樣就可以實(shí)現(xiàn)該接口斗忌,外部類自由繼承,然后自由添加values屬性

下面我們的接口實(shí)體類好了旺聚,需要制作adapter织阳,可是adapter怎么寫呢?我們需要傳入的數(shù)據(jù)類型為Expandable類型砰粹,而且數(shù)據(jù)集合類型要是Expandable的實(shí)現(xiàn)類唧躲,是否可以這樣寫?


class ExpandAdapter<I extends Expandable<I>,VH extends MyViewHolder> extends BackQuickAdapter<I,VH>


這樣保證數(shù)據(jù)集市I類型碱璃,I又是Expandable類型弄痹,這樣可以遍歷I的子數(shù)據(jù)集實(shí)現(xiàn)多級(jí)的展開與隱藏

Adapter具體實(shí)現(xiàn)該怎樣呢?
我們可以在onBindDefViewHolder方法里面添加itemview的點(diǎn)擊事件厘贼,然后為itemview添加tag界酒,tag里面是綁定的數(shù)據(jù),再實(shí)現(xiàn)點(diǎn)擊事件的時(shí)候取出tag里面數(shù)據(jù)嘴秸,判斷單項(xiàng)是否可以展開,如果可以展開,得到子數(shù)據(jù)集放入主數(shù)據(jù)集中岳掐,然后notifyItemRangeInserted就能實(shí)現(xiàn)數(shù)據(jù)的多級(jí)展開

void onBindDefViewHolder(VH holder, int realDataPos) {
    ExpandEntity entity = (ExpandEntity) datas.get(realDataPos);
    ((TextView)holder.itemView.findViewById(R.id.recycler_list_txt)).setText(entity.getValues());
    holder.itemView.setTag(datas.get(realDataPos));
    holder.itemView.setOnClickListener(new ClickDelegate(realDataPos));
}

private class ClickDelegate implements View.OnClickListener{
    //當(dāng)前位置之后插入+headercount
    private int position = 0;

    public ClickDelegate(int position) {
        this.position = position;
    }
    @Override
    public void onClick(View v) {
        Expandable<I> raw = (Expandable<I>) v.getTag();
        if(raw.isExpandable() && !raw.isExpand()){
            //toggle this subItem
            //expand or compose
            datas.addAll(position+1,raw.subItems());
            //from start +2 to datas.size count number
            notifyItemRangeInserted(position + 1 + 1, raw.subItems().size());
            raw.setExpand(true);
            Log.i("itemclick","expand");
        }else if(raw.isExpand()){
            //這里需要折疊凭疮,去除datas中間的數(shù)據(jù),多級(jí)遍歷刪除所有當(dāng)前項(xiàng)的子項(xiàng)
            Log.i("itemclick","compose");
        }
    }
}

注意這里移除操作串述,去除datas中間的數(shù)據(jù)执解,實(shí)現(xiàn)折疊效果,然后notifyItemRangeMoved
這部分的邏輯也是對(duì)主數(shù)據(jù)集datas操作纲酗,這里沒有具體實(shí)現(xiàn)衰腌,有心的小伙伴可以看BRAVH的expand與collapse方法,人家的折疊可是多級(jí)折疊的觅赊,將所有子集都移除然后notifyItemRangeMoved右蕊。這里我就不寫這部分邏輯代碼了。


我是分割線
這里我們寫Adapter需要涉及到一個(gè)泛型的實(shí)例化吮螺,因?yàn)樾枰獙iew加入Viewholder饶囚,并把Viewholder實(shí)例化,而Viewholder又是VH類型的鸠补,所以下面方法我直接貼上代碼

/**
     * 抽象類反射實(shí)例化
     * @param view
     * @return
     */
    protected VH createViewHolder(View view) {
        Class temp = getClass();
        Class z = null;
        while (z == null && null != temp) {
            z = getInstancedGenericKClass(temp);
            temp = temp.getSuperclass();
        }
        VH k;
        // 泛型擦除會(huì)導(dǎo)致z為null
        if (z == null) {
            k = (VH) new MyViewHolder(view);
        } else {
            k = createGenericKInstance(z, view);
        }
        return k != null ? k : (VH) new MyViewHolder(view);
    }
    /**
     * try to create Generic K instance
     *
     * @param z
     * @param view
     * @return
     */
    @SuppressWarnings("unchecked")
    private VH createGenericKInstance(Class z, View view) {
        try {
            Constructor constructor;
            // inner and unstatic class
            if (z.isMemberClass() && !Modifier.isStatic(z.getModifiers())) {
                constructor = z.getDeclaredConstructor(getClass(), View.class);
                constructor.setAccessible(true);
                return (VH) constructor.newInstance(this, view);
            } else {
                constructor = z.getDeclaredConstructor(View.class);
                constructor.setAccessible(true);
                return (VH) constructor.newInstance(view);
            }
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
        return null;
    }
    /**
     * get generic parameter K
     *
     * @param z
     * @return
     */
    private static Class getInstancedGenericKClass(Class z) {
        Type type = z.getGenericSuperclass();
        if (type instanceof ParameterizedType) {
            Type[] types = ((ParameterizedType) type).getActualTypeArguments();
            for (Type temp : types) {
                if (temp instanceof Class) {
                    Class tempClass = (Class) temp;
                    if (MyViewHolder.class.isAssignableFrom(tempClass)) {
                        return tempClass;
                    }
                }
            }
        }
        return null;
    }

這樣泛型的實(shí)例化就完成了~


又到總結(jié)時(shí)間啦萝风。我們模擬BRAVH能夠?qū)W到什么?

我們?cè)趯慉dapter的時(shí)候。將數(shù)據(jù)集類型以泛型的形式傳入紫岩。
在Adapter中抽象出onBindViewHolder,onCreateViewHolder规惰,除了處理預(yù)置的類型,比如頭布局泉蝌,尾布局歇万,空布局,loading布局梨与。其他的都需要自定義ItemType數(shù)據(jù)類型來實(shí)現(xiàn)定制view堕花。
擴(kuò)展與折疊也是屬于自定義數(shù)據(jù)類型中的一種,但是要求傳入的數(shù)據(jù)集類型T中還有T類型的子集合粥鞋,用來得到子集缘挽,這樣可以保持與Adapter
的數(shù)據(jù)類型一直,用于展開刪除其實(shí)就是對(duì)Adapter中的數(shù)據(jù)集datas插入與刪除然后通知刷新而已
拖拽與滑動(dòng)刪除默認(rèn)ItemTouhHelper,在onmoved與onswipe中交換數(shù)據(jù)集中的位置或者刪除某個(gè)位置來通知刷新

Source源代碼

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末呻粹,一起剝皮案震驚了整個(gè)濱河市壕曼,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌等浊,老刑警劉巖腮郊,帶你破解...
    沈念sama閱讀 206,602評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異筹燕,居然都是意外死亡轧飞,警方通過查閱死者的電腦和手機(jī)衅鹿,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,442評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來过咬,“玉大人大渤,你說我怎么就攤上這事〉Ы剩” “怎么了泵三?”我有些...
    開封第一講書人閱讀 152,878評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)衔掸。 經(jīng)常有香客問我烫幕,道長(zhǎng),這世上最難降的妖魔是什么敞映? 我笑而不...
    開封第一講書人閱讀 55,306評(píng)論 1 279
  • 正文 為了忘掉前任较曼,我火速辦了婚禮,結(jié)果婚禮上驱显,老公的妹妹穿的比我還像新娘诗芜。我一直安慰自己,他們只是感情好埃疫,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,330評(píng)論 5 373
  • 文/花漫 我一把揭開白布伏恐。 她就那樣靜靜地躺著端辱,像睡著了一般璧针。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上糊渊,一...
    開封第一講書人閱讀 49,071評(píng)論 1 285
  • 那天胳蛮,我揣著相機(jī)與錄音销凑,去河邊找鬼。 笑死仅炊,一個(gè)胖子當(dāng)著我的面吹牛斗幼,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播抚垄,決...
    沈念sama閱讀 38,382評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼蜕窿,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了呆馁?” 一聲冷哼從身側(cè)響起桐经,我...
    開封第一講書人閱讀 37,006評(píng)論 0 259
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎浙滤,沒想到半個(gè)月后阴挣,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,512評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡纺腊,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,965評(píng)論 2 325
  • 正文 我和宋清朗相戀三年畔咧,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了茎芭。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,094評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡盒卸,死狀恐怖骗爆,靈堂內(nèi)的尸體忽然破棺而出次氨,到底是詐尸還是另有隱情蔽介,我是刑警寧澤,帶...
    沈念sama閱讀 33,732評(píng)論 4 323
  • 正文 年R本政府宣布煮寡,位于F島的核電站虹蓄,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏幸撕。R本人自食惡果不足惜薇组,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,283評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望坐儿。 院中可真熱鬧律胀,春花似錦、人聲如沸貌矿。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,286評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽逛漫。三九已至黑低,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間酌毡,已是汗流浹背克握。 一陣腳步聲響...
    開封第一講書人閱讀 31,512評(píng)論 1 262
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留枷踏,地道東北人菩暗。 一個(gè)月前我還...
    沈念sama閱讀 45,536評(píng)論 2 354
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像旭蠕,于是被迫代替她去往敵國和親停团。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,828評(píng)論 2 345

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