【Android】快速開發(fā)偷懶必備歪玲,一句話搞定所有ViewGroup的Adapter . 支持自定義ViewGroup

轉(zhuǎn)載請標明出處:
http://www.reibang.com/p/5ad655759c28
本文出自:【張旭童的簡書】 (http://www.reibang.com/users/8e91ff99b072/latest_articles)
代碼傳送門:喜歡的話函筋,隨手點個star。多謝
https://github.com/mcxtzhang/all-base-adapter

概述

開發(fā)中,經(jīng)常會用到動態(tài)在ScrollView、LinearLayout里addView的事馋艺,尤其是ItemView一樣時,每次都要寫一大堆代碼 inflater 動態(tài)addView迈套,很煩捐祠。

還有就是在嵌套ListView、ScrollView時桑李,想采用LinearLayout替代(這樣性能更佳踱蛀,不明白的看一個控件搞定嵌套ListView)窿给,但動態(tài)addView步驟神煩。

這個時候就開始期待率拒,能不能有一種快速為任意ViewGroup添加子View的東西崩泡。

我之前為此事特意寫過一篇LinearLayout封裝博文,封裝了一個控件使用猬膨。試圖一個控件搞定嵌套ListView角撞。但是后來發(fā)現(xiàn),采用繼承某個ViewGroup做這個事情不夠優(yōu)雅 寥掐,對代碼有侵入性靴寂,如果有其他ViewGroup需要動態(tài)addView,就會寫重復的代碼 召耘。

前幾天有人在群里問百炬,如何方便的給ScrollView動態(tài)添加不同種類型的childView,類似RecyclerView那樣污它。我之前的封裝由于內(nèi)部有一個簡單的重用機制剖踊,只支持單一ItemType,也不支持多種類型的childView衫贬。

那么需求就來了:

  • 快速簡單使用
  • 支持任意ViewGroup
  • 無耦合
  • 無侵入性
  • Item支持多種類型

除此之外德澈,我還加入:

  • 為ItemView設置OnItemClickListener
  • 為ItemView設置OnItemLongClickListener

本文就封裝了這么一個東西。

核心:

  • 利用Adapter模式封裝getView的操作
  • 搭配一個工具類固惯,為所有ViewGroup addView梆造。
  • 再封裝出兩個使用快速簡單的Adapter 分別用于添加 單一Item布局、多種Item布局葬毫。

PS:所以本文也算是填了之前的一個坑镇辉,在之前適配器模式博文文末,我就提到要寫一篇為流式布局增加Adapter的文章贴捡,作為Adapter的實戰(zhàn)演練忽肛。使用本文封裝的Adapter自然可以達到這一點。

由于采用Adapter隔離ViewGroup和ItemView烂斋,在切換ViewGroup時屹逛,十分方便。
如:在需求讓你把一個HorizontalScrollView包裹的水平標簽轉(zhuǎn)換成流式布局時汛骂,只需要在xml替換控件即可罕模。Adapter將自動完成適配的工作。其他代碼一句不用修改香缺。

不BB了手销,先看看以后如何使用吧,夠不夠簡單粗暴图张。

使用預覽

單一Item類型:

Adapter泛型傳入JavaBean锋拖,構造函數(shù)傳入數(shù)據(jù)集和layout布局诈悍,一句代碼搞定:

        //單一ItemView
        ViewGroupUtils.addViews(mLinearLayout, new SingleAdapter<TestBean>(this, mDatas, R.layout.item_test) {
            @Override
            public void onBindView(ViewGroup parent, View itemView, TestBean data, int pos) {
                Glide.with(LinearLayoutActivity.this)
                        .load(data.getAvatar())
                        .into((ImageView) itemView.findViewById(R.id.ivAvatar));
                ((TextView) itemView.findViewById(R.id.tvName)).setText(data.getName());
            }
        });

效果:


以前會用ScrollView嵌套ListView,現(xiàn)在只要用ScrollView套LinearLayout即可兽埃,性能更佳侥钳。

多種Item類型:

多種Item類型分兩種情況:

數(shù)據(jù)結構相同:

數(shù)據(jù)結構相同依然可以給Adapter傳入泛型,避免強轉(zhuǎn):

        //多種ItemViewType柄错,但是數(shù)據(jù)結構相同舷夺,可以傳入數(shù)據(jù)結構泛型,避免強轉(zhuǎn)
        ViewGroupUtils.addViews(linearLayout, new MulTypeAdapter<MulTypeBean>(this, initDatas()) {
            @Override
            public void onBindView(ViewGroup parent, View itemView, MulTypeBean data, int pos) {
                ((TextView) itemView.findViewById(R.id.tvWords)).setText(data.getName() + "");
                Glide.with(MulTypeActivity.this)
                        .load(data.getAvatar())
                        .into((ImageView) itemView.findViewById(ivAvatar));
            }
        });

效果:

多種Item售貌,數(shù)據(jù)結構相同给猾。
多種Item,數(shù)據(jù)結構相同颂跨。

數(shù)據(jù)結構不同:

如果數(shù)據(jù)結構不同敢伸,則不用傳入泛型,但是使用時需要強轉(zhuǎn):

        //多種Item類型:數(shù)據(jù)結構不同 不傳泛型了 使用時需要強轉(zhuǎn)javaBean恒削,判斷ItemLayoutId
        ViewGroupUtils.addViews((ViewGroup) findViewById(R.id.activity_mul_type_mul_bean), new MulTypeAdapter(this, datas) {
            @Override
            public void onBindView(ViewGroup parent, View itemView, IMulTypeHelper data, int pos) {
                switch (data.getItemLayoutId()) {
                    case R.layout.item_mulbean_1:
                        MulBean1 mulBean1 = (MulBean1) data;
                        Glide.with(MulTypeMulBeanActivity.this)
                                .load(mulBean1.getUrl())
                                .into((ImageView) itemView);
                        break;
                    case R.layout.item_mulbean_2:
                        MulBean2 mulBean2 = (MulBean2) data;
                        TextView tv = (TextView) itemView;
                        tv.setText(mulBean2.getName());
                }
            }
        });

數(shù)據(jù)結構:

public class MulBean1 implements IMulTypeHelper {
    private String url;
    @Override
    public int getItemLayoutId() {
        return R.layout.item_mulbean_1;
    }
}
public class MulBean2 implements IMulTypeHelper {
    private String name;
    @Override
    public int getItemLayoutId() {
        return R.layout.item_mulbean_2;
    }
}

Item1布局是一個ImageView池颈,Item2布局是一個TextView
效果:


這次用橫向展示 多種Item,數(shù)據(jù)結構不同钓丰。
這次用橫向展示 多種Item躯砰,數(shù)據(jù)結構不同。

Item點擊事件

item的點擊和長按等事件携丁,有兩種方法設置,這里以點擊事件為例琢歇,長按事件同理:

Adapter.onBindView()里設置

Adapter.onBindView()方法里能拿到ItemView,自然就可以設置各種事件梦鉴。類似RecyclerView矿微。

在這里設置優(yōu)先級更高。原因后文會提到尚揣。

@Override
            public void onBindView(ViewGroup parent, View itemView, final MulTypeBean data, int pos) {
                ....
                itemView.setOnClickListener(new View.OnClickListener() {
                    @Override
                    public void onClick(View view) {
                        Toast.makeText(mContext, "onBindView里設置:文字是:" + data.getName(), Toast.LENGTH_SHORT).show();
                    }
                });
            }

通過ViewGroupUtils設置

可以在ViewGroupUtils.addViews直接作為參數(shù)傳入.

也可以用ViewGroupUtils.setOnItemClickListener()設置 。

優(yōu)先級比Adapter.onBindView()里設置低掖举,原因后文會提到快骗。

        //設置OnItemClickListener
        OnItemClickListener onItemClickListener = new OnItemClickListener() {
            @Override
            public void onItemClick(ViewGroup parent, View itemView, int position) {
                Toast.makeText(MulTypeActivity.this, "通過OnItemClickListener設置:" + position, Toast.LENGTH_SHORT).show();
            }
        };
        //可以在`ViewGroupUtils.addViews`直接作為參數(shù)傳入.\
        ViewGroupUtils.addViews(linearLayout, adapter ,onItemClickListener);
        //或者 也可以用`ViewGroupUtils.setOnItemClickListener()`設置
        ViewGroupUtils.setOnItemClickListener(linearLayout,onItemClickListener);
        

看起來還是挺好的,嗯~至少我自己這么覺得塔次,我個人比較喜歡這種0耦合方篮,每一個庫都像可組裝拆卸的機關槍一樣,拿起來就用励负。而不是笨重功能繁多的重裝坦克藕溅。
搭配我的得意之作,每次必安利的史上集成最簡單側滑菜單控件继榆。
效果如下:

文首提到的巾表,一開始是個水平ScrollView
文首提到的汁掠,一開始是個水平ScrollView
替換成流式布局
替換成流式布局

無特殊設置,僅僅替換ViewGroup為流式布局集币,替換Item根布局為我擼的側滑菜單庫考阱,能感受到這種0耦合的庫的魅力了么。23333333 鞠苟。

設計思路

下面就讓我手摸手帶大家實現(xiàn)它乞榨。
先看類圖。

UML類圖:

先簡要概括

  • 我們的頂層接口IViewGroupAdapter暴露出兩個方法供ViewGroup使用当娱。

  • ViewGroupUtils 是為任意ViewGroup 動態(tài)addView的工具類吃既,只依賴于 IViewGroupAdapter 接口即可完成工作。

  • BaseAdapter是第二層跨细,在這一層引入了數(shù)據(jù)集鹦倚,用List<T>保存。實現(xiàn)IViewGroupAdapter的方法,重載一個三參數(shù)的getView()方法扼鞋,供子類去實現(xiàn)申鱼。

  • SingleAdapter是第三層,一個簡化的Adapter,只支持單種Item,以LayoutId 構建View。實現(xiàn)getView()方法云头,并暴露出onBindView()供用戶快速使用捐友。

  • MulTypeAdapter也同處第三層,一個支持多種Item的Adapter溃槐。依賴IMulTypeHelper接口匣砖,利用其getItemLayoutId() 方法去實現(xiàn)getView()方法,并暴露出onBindView()供用戶快速使用昏滴。

頂層接口設計

頂層接口猴鲫,即IViewGroupAdapter

根據(jù)迪米特法則(最少知道原則),我們應該抽象出一個頂層的接口谣殊,對ViewGroup暴露出最少的方法供使用拂共。

我們想一下,對于ViewGroup姻几,它最少只需要哪些就能完成我們的需求宜狐。

  • ChildView是什么---> View
  • 有多少ChildView 需要 添加--->count
    所以,我們的最頂層接口如下編寫:
public interface IViewGroupAdapter {
    /**
     * ViewGroup調(diào)用獲取ItemView
     *
     * @param parent
     * @param pos
     * @return
     */
    View getView(ViewGroup parent, int pos);

    /**
     * ViewGroup調(diào)用蛇捌,得到ItemCount
     *
     * @return
     */
    int getCount();
}

ok抚恒,代碼寫到這里,后面的我們暫且不提络拌,我們就可以寫動態(tài)addView的工具類了俭驮。因為我們的ViewGroup依賴的所有信息都由IViewGroupAdapter這個接口提供了。

工具類

ViewGroupUtils 是為任意ViewGroup 動態(tài)addView的工具類春贸,不考慮點擊事件的情況下混萝,只依賴于 IViewGroupAdapter 接口即可完成工作遗遵。
如下編寫:

    /**
     * 為任意ViewGroup 添加ItemViews.
     *
     * @param viewGroup               必傳
     * @param adapter                 必傳,至少提供要add的View和需要add的count
     * @param removeViews             是否需要remove掉之前的Views
     */
    public static void addViews(final ViewGroup viewGroup, IViewGroupAdapter adapter
            , boolean removeViews) {
        if (viewGroup == null || adapter == null) {
            return;
        }
        //如果需要remove掉之前的Views
        if (removeViews && viewGroup.getChildCount() > 0) {
            viewGroup.removeAllViews();
        }
        //開始添加子Views,通過Adapter獲得需要添加的Count
        int count = adapter.getCount();
        for (int i = 0; i < count; i++) {
            //通過Adapter獲得ItemView
            View itemView = adapter.getView(viewGroup, i);
            viewGroup.addView(itemView);
    
        }
    }

如此即可完成 動態(tài)給任意ViewGroup addView 的工作譬圣。

不過我們開頭提過瓮恭,我還是想引入ItemView的點擊和長按事件的。但是關于這兩個ItemListener厘熟,還是有一些東西要考慮的屯蹦。

ItemListener的設計

為ViewGroup提供OnItemClickListener,有個問題需要考慮:
如果使用者調(diào)用了setOnItemClickListener绳姨,且在Adapter里自己又對ItemView設置了OnClickListener登澜,那么究竟該觸發(fā)哪個Listener,即它們的優(yōu)先級飘庄。

我們不應該自己靠腦子想答案脑蠕,還是參照系統(tǒng)原有的設計比較好。既然ListView提供了OnItemClickListener跪削,那么我們參照它的設計來就行谴仙。

先說結論:通過參照ListView的源碼,以及實驗得知碾盐,對ItemViewOnClickListener優(yōu)先級 > ViewGroup的OnItemClickListener晃跺。

為什么?答案在源碼中毫玖,感興趣看掀虎,不感興趣直接跳過。

從AbsListView的onTouchEvent()->onTouchUp()->PerformClick->performItemClick-> AdapterView.performItemClick() -> AdapterView.mOnItemClickListener付枫,即可找到答案烹玉。

這里不詳細分析源碼,不是本文重點阐滩,簡單的說二打,從入口處是AbsListView的onTouchEvent() ,我們可以知道,ListView本身并沒有干預ItemView的點擊事件(即沒有為其設置OnClickListener)掂榔,是在ItemView不消耗Touch事件時 才進行Item點擊事件的觸發(fā)址儒。
因此若ItemView設置了OnClickListener,AbsListView的onTouchEvent()將收不到MotionEvent.ACTION_UP事件衅疙,因而也不會觸發(fā)OnItemClickListener。所以這決定了ItemViewOnClickListener優(yōu)先級高鸳慈。

還有一個問題饱溢,我們可以通過View.hasOnClickListeners()這個方法來判斷View是否設置了OnClickListener,但是這個方法在API15才加入走芋,為了能兼容低版本欲逃,我采用了另一種方法判斷刹泄,itemView.isClickable()女揭,如果true,我當做有點擊事件溉仑,如果false,我當做沒有状植。

其實在ListView中這個問題也是一樣的浊竟,itemView.isClickable()為true的話,點擊事件就被攔截住津畸,不會分發(fā)至AbsListView的onTouchEvent()里了振定。所以我們這么寫是沒問題,并且是正確的肉拓。

ItemListener的完整實現(xiàn):

既然如此后频,那么我們在程序中,應該如下編寫:

        for (int i = 0; i < count; i++) {
            View itemView = adapter.getView(viewGroup, i);
            viewGroup.addView(itemView);
            //添加點擊事件
            if (null != onItemClickListener && !itemView.isClickable()) {
                final int finalI = i;
                itemView.setOnClickListener(new View.OnClickListener() {
                    @Override
                    public void onClick(View view) {
                        onItemClickListener.onItemClick(viewGroup, view, finalI);
                    }
                });
            }
            //添加點擊事件
            if (null != onItemLongClickListener && !itemView.isLongClickable()) {
                final int finalI = i;
                itemView.setOnLongClickListener(new View.OnLongClickListener() {
                    @Override
                    public boolean onLongClick(View view) {
                        return onItemLongClickListener.onItemLongClick(viewGroup, view, finalI);
                    }
                });
            }
        }

所以完整的addViews()如下:

    /**
     * 為任意ViewGroup 添加ItemViews.
     *
     * @param viewGroup               必傳
     * @param adapter                 必傳暖途,至少提供要add的View和需要add的count
     * @param removeViews             是否需要remove掉之前的Views
     * @param onItemClickListener     Item點擊事件
     * @param onItemLongClickListener Item長按事件
     */
    public static void addViews(final ViewGroup viewGroup, IViewGroupAdapter adapter
            , boolean removeViews
            , final OnItemClickListener onItemClickListener
            , final OnItemLongClickListener onItemLongClickListener) {
        if (viewGroup == null || adapter == null) {
            return;
        }
        //如果需要remove掉之前的Views
        if (removeViews && viewGroup.getChildCount() > 0) {
            viewGroup.removeAllViews();
        }
        //開始添加子Views,通過Adapter獲得需要添加的Count
        int count = adapter.getCount();
        for (int i = 0; i < count; i++) {
            //通過Adapter獲得ItemView
            View itemView = adapter.getView(viewGroup, i);
            viewGroup.addView(itemView);
            //添加點擊事件,itemView之前沒有點擊事件才會去設置
            if (null != onItemClickListener && !itemView.isClickable()) {
                final int finalI = i;
                itemView.setOnClickListener(new View.OnClickListener() {
                    @Override
                    public void onClick(View view) {
                        onItemClickListener.onItemClick(viewGroup, view, finalI);
                    }
                });
            }
            //添加長按事件itemView之前沒有長按事件才會去設置
            if (null != onItemLongClickListener && !itemView.isLongClickable()) {
                final int finalI = i;
                itemView.setOnLongClickListener(new View.OnLongClickListener() {
                    @Override
                    public boolean onLongClick(View view) {
                        return onItemLongClickListener.onItemLongClick(viewGroup, view, finalI);
                    }
                });
            }
        }
    }

實際中卑惜,我們可能不需要設置Listener,為了快速使用驻售,我又提供了兩個重載方法:

    /**
     * 為任意ViewGroup 添加ItemViews.
     * 并且會清除掉之前所有add過的View
     *
     * @param viewGroup 必傳
     * @param adapter   必傳露久,至少提供要add的View和需要add的count
     */
    public static void addViews(final ViewGroup viewGroup, IViewGroupAdapter adapter) {
        addViews(viewGroup, adapter, true, null, null);
    }

    /**
     * 為任意ViewGroup 添加ItemViews.
     * 并且會清除掉之前所有add過的View
     *
     * @param viewGroup           必傳
     * @param adapter             必傳,至少提供要add的View和需要add的count
     * @param onItemClickListener Item點擊事件
     */
    public static void addViews(final ViewGroup viewGroup, IViewGroupAdapter adapter
            , final OnItemClickListener onItemClickListener) {
        addViews(viewGroup, adapter, true, onItemClickListener, null);
    }

若不在addViews()里設置ItemListener芋浮,也可以通過setOnItemClickListener()setOnItemLongClickListener() 設置抱环,不過這兩個方法必須在addViews()方法之后調(diào)用:

    /**
     * 為任意ViewGroup設置OnItemClickListener.
     * 該方法必須在addViews()方法之后調(diào)用,否則無效纸巷。
     * 因為ItemView 必須被添加在ViewGroup里才能遍歷到镇草。
     * 建議直接在addViews()方法里傳入OnItemClickListener進行設置,性能更高
     *
     * @param viewGroup
     * @param onItemClickListener
     */
    public static void setOnItemClickListener(final ViewGroup viewGroup, final OnItemClickListener onItemClickListener) {
        if (viewGroup == null || onItemClickListener == null) {
            return;
        }
        int childCount = viewGroup.getChildCount();
        for (int i = 0; i < childCount; i++) {
            final View itemView = viewGroup.getChildAt(i);
            //itemView之前沒有點擊事件才會去設置
            if (null != itemView && !itemView.isClickable()) {
                final int finalI = i;
                itemView.setOnClickListener(new View.OnClickListener() {
                    @Override
                    public void onClick(View view) {
                        onItemClickListener.onItemClick(viewGroup, itemView, finalI);
                    }
                });
            }
        }
    }


    /**
     * 為任意ViewGroup設置OnItemLongClickListener.
     * 該方法必須在addViews()方法之后調(diào)用瘤旨,否則無效梯啤。
     * 因為ItemView 必須被添加在ViewGroup里才能遍歷到。
     * 建議直接在addViews()方法里傳入OnItemLongClickListener進行設置存哲,性能更高
     *
     * @param viewGroup
     * @param onItemLongClickListener
     */
    public static void setOnItemLongClickListener(final ViewGroup viewGroup, final OnItemLongClickListener onItemLongClickListener) {
        if (viewGroup == null || onItemLongClickListener == null) {
            return;
        }
        int childCount = viewGroup.getChildCount();
        for (int i = 0; i < childCount; i++) {
            final View itemView = viewGroup.getChildAt(i);
            //itemView之前沒有長按事件才會去設置
            if (null != itemView && !itemView.isLongClickable()) {
                final int finalI = i;
                itemView.setOnLongClickListener(new View.OnLongClickListener() {
                    @Override
                    public boolean onLongClick(View view) {
                        return onItemLongClickListener.onItemLongClick(viewGroup, itemView, finalI);
                    }
                });
            }
        }
    }

Adapter

終于到了我們的重頭戲因宇,Adapter。

BaseAdapter

BaseAdapter是第二層祟偷,在這一層引入了數(shù)據(jù)集察滑,用List<T>保存。實現(xiàn)IViewGroupAdapter的方法,重載一個三參數(shù)的getView()方法修肠,供子類去實現(xiàn)贺辰。

它和我們平時寫的ListView、RecyclerView的Adapter就比較像了,我也是參照平時的寫法饲化。

核心就是實現(xiàn)IViewGroupAdaptergetView(ViewGroup parent, int pos)方法,增加一個數(shù)據(jù)莽鸭,工作轉(zhuǎn)交給三參數(shù)的getView(ViewGroup parent, int pos, T data)方法。

子類應該 實現(xiàn) getView(ViewGroup parent, int pos, T data)方法吃靠,在其中inflate or new 出 ItemView硫眨,并綁定數(shù)據(jù)

public abstract class BaseAdapter<T> implements IViewGroupAdapter {
    protected List<T> mDatas;
    protected Context mContext;
    protected LayoutInflater mInflater;

    /**
     * ViewGroup調(diào)用獲取ItemView,create bind一起做
     *
     * @param parent
     * @param pos
     * @return
     */
    @Override
    public View getView(ViewGroup parent, int pos) {
        return getView(parent, pos, mDatas.get(pos));
    }

    /**
     * 實際的createItemView的地方
     *
     * @param parent
     * @param pos
     * @param data
     * @return
     */
    public abstract View getView(ViewGroup parent, int pos, T data);

    /**
     * ViewGroup調(diào)用巢块,得到ItemCount
     *
     * @return
     */
    @Override
    public int getCount() {
        return mDatas != null ? mDatas.size() : 0;
    }

}

SingleAdapter

SingleAdapter是第三層,一個簡化的Adapter,只支持單種Item,以LayoutId 構建View礁阁。實現(xiàn)getView()方法,并暴露出onBindView()供用戶快速使用夕冲。

使用時氮兵,一般將數(shù)據(jù)結構的泛型傳入,配合構造函數(shù)傳入的ItemLayoutId使用歹鱼。

它繼承自BaseAdapter,所以它了實現(xiàn)getView(ViewGroup parent, int pos, T data)方法泣栈。在根據(jù)傳入的itemLayoutId inflate出ItemView后,會回調(diào)onBindView(ViewGroup parent, View itemView, T data, int pos)方法弥姻,并返回ItemView供ViewGroup使用南片。

onBindView(ViewGroup parent, View itemView, T data, int pos)方法里,我們完成數(shù)據(jù)綁定的工作庭敦。例如加載圖片疼进,也可以設置點擊事件。


public abstract class SingleAdapter<T> extends BaseAdapter<T> {

    private int mItemLayoutId;

    @Override
    public View getView(ViewGroup parent, int pos, T data) {
        //實現(xiàn)getView
        View itemView = /*onCreateView(parent, pos)*/mInflater.inflate(mItemLayoutId, parent, false);
        onBindView(parent, itemView, data, pos);
        return itemView;
    }

    /**
     * 暴漏這個 讓外部bind數(shù)據(jù)
     *
     * @param parent
     * @param itemView
     * @param data
     * @param pos
     */
    public abstract void onBindView(ViewGroup parent, View itemView, T data, int pos);

}

MulTypeAdapter

MulTypeAdapter也同處第三層秧廉,一個支持多種Item的Adapter伞广。依賴IMulTypeHelper接口,利用其getItemLayoutId() 方法去實現(xiàn)getView()方法疼电,并暴露出onBindView()供用戶快速使用嚼锄。

public abstract class MulTypeAdapter<T extends IMulTypeHelper> extends BaseAdapter<T> {

    @Override
    public View getView(ViewGroup parent, int pos, T data) {
        View itemView = mInflater.inflate(data.getItemLayoutId(), parent, false);
        onBindView(parent, itemView, data, pos);
        return itemView;
    }

    /**
     * 暴漏這個 讓外部bind數(shù)據(jù)
     *
     * @param parent
     * @param itemView
     * @param data
     * @param pos
     */
    public abstract void onBindView(ViewGroup parent, View itemView, T data, int pos);
}

IMulTypeHelper接口,同樣簡單:

public interface IMulTypeHelper {
    int getItemLayoutId();
}

總結

代碼傳送門:喜歡的話,隨手點個star蔽豺。多謝
https://github.com/mcxtzhang/all-base-adapter

因為想支持任意ViewGroup区丑,對ViewGroup代碼無侵入性,因而對部分功能進行了取舍修陡,例如設置OnItemXXXListener,如果采用繼承ViewGroup沧侥,嵌入代碼,可以做到不強制addViews()setOnItemClickListener()順序魄鸦。

通過上文我們能感受到一些面向接口編程的奧義宴杀,例如我們只需要設計好頂層的接口IViewGroupAdapter,在沒寫剩下的xxxAdapter時拾因,工具類都可以寫好旺罢,編譯通過斯棒。
這在以后擴展時,例如主经,我數(shù)據(jù)集不能用List來保存了,我可能是多個List or Map 等等庭惜,只需要實現(xiàn)IViewGroupAdapter接口即可定制一個Adapter罩驻。其他代碼不需任何修改。

有人說過护赊,設計模式怎么學惠遏,就是先學完一遍所有的設計模式。然后再全部忘掉他們骏啰,只要記住SOLID原則即可节吮。
我覺得很有道理,就像我之前一直在糾結代理模式和裝飾者模式的區(qū)別判耕,后來我想透绩,編碼時,我管它是什么模式壁熄,只要寫出來的是易維護的代碼即可帚豪。

to do list

  • 考慮加入復用緩存池
  • 考慮替換onBindView()ItemView->通用的ViewHolder,這樣可以少寫一些findViewById()代碼
  • 整合DataBinding 的通用Adapter入庫草丧。
  • 整合 RecyclerView狸臣、ListView的通用Adapter入庫。
  • 加入一些自定義ViewGroup入庫昌执,例如流式布局烛亦,九宮格,Banner輪播圖懂拾。

下文預告:

一個用ScrollView很容易實現(xiàn)煤禽,但RecyclerView、ListView就無法實現(xiàn)的動畫效果委粉,仿淘寶會員中心等級動畫呜师。凸顯為所有ViewGroup增加Adapter模式的重要性。

DataBinding篇隆重登場

感興趣可以去閱讀
http://www.reibang.com/p/5ad655759c28

轉(zhuǎn)載請標明出處:
http://www.reibang.com/p/5ad655759c28
本文出自:【張旭童的簡書】 (http://www.reibang.com/users/8e91ff99b072/latest_articles)
代碼傳送門:喜歡的話贾节,隨手點個star汁汗。多謝
https://github.com/mcxtzhang/all-base-adapter

最后編輯于
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市栗涂,隨后出現(xiàn)的幾起案子知牌,更是在濱河造成了極大的恐慌,老刑警劉巖斤程,帶你破解...
    沈念sama閱讀 206,311評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件角寸,死亡現(xiàn)場離奇詭異菩混,居然都是意外死亡,警方通過查閱死者的電腦和手機扁藕,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,339評論 2 382
  • 文/潘曉璐 我一進店門沮峡,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人亿柑,你說我怎么就攤上這事邢疙。” “怎么了望薄?”我有些...
    開封第一講書人閱讀 152,671評論 0 342
  • 文/不壞的土叔 我叫張陵疟游,是天一觀的道長。 經(jīng)常有香客問我痕支,道長颁虐,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,252評論 1 279
  • 正文 為了忘掉前任卧须,我火速辦了婚禮另绩,結果婚禮上,老公的妹妹穿的比我還像新娘故慈。我一直安慰自己板熊,他們只是感情好,可當我...
    茶點故事閱讀 64,253評論 5 371
  • 文/花漫 我一把揭開白布察绷。 她就那樣靜靜地躺著干签,像睡著了一般。 火紅的嫁衣襯著肌膚如雪拆撼。 梳的紋絲不亂的頭發(fā)上容劳,一...
    開封第一講書人閱讀 49,031評論 1 285
  • 那天,我揣著相機與錄音闸度,去河邊找鬼竭贩。 笑死,一個胖子當著我的面吹牛莺禁,可吹牛的內(nèi)容都是我干的留量。 我是一名探鬼主播,決...
    沈念sama閱讀 38,340評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼哟冬,長吁一口氣:“原來是場噩夢啊……” “哼楼熄!你這毒婦竟也來了?” 一聲冷哼從身側響起浩峡,我...
    開封第一講書人閱讀 36,973評論 0 259
  • 序言:老撾萬榮一對情侶失蹤可岂,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后翰灾,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體缕粹,經(jīng)...
    沈念sama閱讀 43,466評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡稚茅,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,937評論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了平斩。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片亚享。...
    茶點故事閱讀 38,039評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖绘面,靈堂內(nèi)的尸體忽然破棺而出虹蒋,到底是詐尸還是另有隱情,我是刑警寧澤飒货,帶...
    沈念sama閱讀 33,701評論 4 323
  • 正文 年R本政府宣布,位于F島的核電站峭竣,受9級特大地震影響塘辅,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜皆撩,卻給世界環(huán)境...
    茶點故事閱讀 39,254評論 3 307
  • 文/蒙蒙 一扣墩、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧扛吞,春花似錦呻惕、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,259評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至盲泛,卻和暖如春濒持,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背寺滚。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評論 1 262
  • 我被黑心中介騙來泰國打工柑营, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人村视。 一個月前我還...
    沈念sama閱讀 45,497評論 2 354
  • 正文 我出身青樓官套,卻偏偏與公主長得像,于是被迫代替她去往敵國和親蚁孔。 傳聞我的和親對象是個殘疾皇子奶赔,可洞房花燭夜當晚...
    茶點故事閱讀 42,786評論 2 345

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