Android TabContainerView 實(shí)現(xiàn)底部導(dǎo)航欄效果 V2.0

我們先來看看效果圖


xiaoguo.gif

從效果圖中可以看出V2.0和V1.0的區(qū)別
V2.0的Tab UI是可以實(shí)現(xiàn)高度定制的,上面的效果圖中Tab UI共有三種樣式。
V1.0的Tab UI是定死的

實(shí)現(xiàn)

項(xiàng)目的整體架構(gòu)基本沒變,不了解項(xiàng)目架構(gòu)的可以先看看V1.0的文章(http://www.itdecent.cn/p/7cccb5c054da#
V2.0相對(duì)于V1.0來說就是刪除了Tab類,新增了一個(gè)抽象類AbsTab,同時(shí)修改了BaseAdapter類的邏輯,下面我們先來看看AbsTab類

public abstract class AbsTab {

    protected Context mContext;
    /**
     *  Tab在TabHost中的位置,屬于第mIndex個(gè)
     */
    private int mIndex;

    /**
     *  Tab類的資源View布局
     */
    private View mRootView;

    /**
     *  當(dāng)前Tab是否選中
     */
    protected boolean mIsSelected;

    /**
     *  Tab選中監(jiān)聽
     */
    private OnTabSelectedListener onTabSelectedListener;

    public AbsTab(Context context, int index) {
        mContext = context;
        mIndex = index;
    }

    /**
     *  初始化View資源,得到RootView,并添加響應(yīng)事件
     * @param tab
     * @param layoutResId
     * @return
     */
    protected void inflaterView(final AbsTab tab, @LayoutRes int layoutResId) {
        mRootView = LayoutInflater.from(mContext).inflate(layoutResId, null);
        LinearLayout.LayoutParams rootViewLp = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
        rootViewLp.weight = 1;
        mRootView.setLayoutParams(rootViewLp);

        initView(mRootView);
        mRootView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (onTabSelectedListener != null) {
                    onTabSelectedListener.onTabSelected(tab);
                }
            }
        });
    }

    /**
     *  設(shè)置選中監(jiān)聽
     * @param onTabSelectedListener
     */
    public void setOnTabSelectedListener(OnTabSelectedListener onTabSelectedListener) {
        this.onTabSelectedListener = onTabSelectedListener;
    }



    /**
     *  得到Tab 的RootView
     * @return  View
     */
    public View getTabRootView() {
        return mRootView;
    }

    /**
     *  得到Tab Index
     * @return int
     */
    public int getTabIndex() {
        return  mIndex;
    }

    /**
     *  顯示消息提示
     * @param show 是否顯示
     * @param count 顯示數(shù)量
     */
    public void showMessageTip(boolean show, int count) {};

    /**
     * 是否選中該Tab
     * @param isSelected
     */
    protected abstract void tabSelected(boolean isSelected);
    
     /**
     *  初始化RootView里的布局
     * @param rootView
     */
     protected abstract void initView(View rootView);
}

AbsTab類中的屬性和方法上都有明確的注釋,無需過多的解釋,下面再來看看BaseAdapter類做了什么修改

public abstract class BaseAdapter {

    private Fragment[] mFragmentArray;
    private FragmentManager mFragmentManager;
    protected Context mContext;

    public BaseAdapter(Context context, Fragment[] fragments, FragmentManager fragmentManager) {
        mContext = context;
        mFragmentArray = fragments;
        mFragmentManager = fragmentManager;
    }

    /**
     *  tab數(shù)量
     */
    public int getCount() {
        return mFragmentArray != null ? mFragmentArray.length : 0;
    }

    /**
     * fragment 數(shù)組
     */
    public Fragment[] getFragmentArray() {
        return mFragmentArray;
    }

    public FragmentManager getFragmentManager() {
        return mFragmentManager;
    }

    /**
     *  得到tab
     * @return
     */
    public abstract AbsTab getTab(int index);

BaseAdapter類刪除了getTextArray,getIconImageArray,getSelectedIconImageArray三個(gè)方法,新增加了getTab抽象方法。

使用

首先創(chuàng)建一個(gè)繼承自AbsTab類的Tab類(項(xiàng)目中我默認(rèn)實(shí)現(xiàn)了一個(gè)DefaultTab),然后創(chuàng)建一個(gè)繼承自BaseAdapter類的適配器類(項(xiàng)目中我默認(rèn)實(shí)現(xiàn)了一個(gè)DefaultAdapter)

 TabContainerView tabContainerView = (TabContainerView) findViewById(R.id.tab_containerview_main);
 tabContainerView.setAdapter(new DefaultAdapter(this, fragments, getSupportFragmentManager(), getResources().getStringArray(R.array.titleArray),
 getResources().getColor(R.color.colorPrimary), iconImageArray, selectedIconImageArray));

在使用上和V1.0是一致的,最大的不同的是適配器,我們來看看DefaultAdapter適配器

public class DefaultAdapter extends BaseAdapter {

    private String[] mTextArray;
    private int mTextColor = Color.BLACK, mSelectedTextColor;
    private int[] mIconImageArray;
    private int[] mSelectedIconImageArray;

    public DefaultAdapter(Context context, Fragment[] fragmentArray, FragmentManager fragmentManager, String[] textArray, int selectTextColor,
                          int[] iconImageArray, int[] selectedIconImageArray) {
       super(context, fragmentArray, fragmentManager);

        mTextArray = textArray;
        mSelectedTextColor = selectTextColor;
        mIconImageArray = iconImageArray;
        mSelectedIconImageArray = selectedIconImageArray;
    }


    @Override
    public AbsTab getTab(int index) {
        DefaultTab defaultTab = new DefaultTab(mContext, index);
        defaultTab.setText(mTextArray[index]);
        defaultTab.setTextColor(mTextColor, mSelectedTextColor);
        defaultTab.setIconImage(mIconImageArray[index], mSelectedIconImageArray[index]);
        return defaultTab;
    }

}

重點(diǎn)來看看getTab方法,方法中創(chuàng)建了一個(gè)DefaultTab類,DefaultTab是什么呢?我們進(jìn)來看看他的具體實(shí)現(xiàn)

public class DefaultTab extends AbsTab {

    /**
     *  tab布局信息
     */
    private ImageView mIvIcon;
    private TextView mTvText;
    private MessageCircle mMessageCircleTip;

    /**
     *  tab 文本顏色和圖片切換資源
     */
    private int mTextColor;
    private int mSelectedTextColor;
    private int mIconImage;
    private int mSelectedIconImage;

    public DefaultTab(Context context, int index) {
       super(context, index);

        inflaterView(this, R.layout.tab_default);
    }

    @Override
    public void tabSelected(boolean isSelected) {
        if (this.mIsSelected == isSelected) return;

        mIvIcon.setImageResource(isSelected ? mSelectedIconImage : mIconImage);
        mTvText.setTextColor(isSelected ? mSelectedTextColor : mTextColor);
        this.mIsSelected = isSelected;
    }

    @Override
    public void showMessageTip(boolean show, int count) {
        mMessageCircleTip.setVisibility(show ? View.VISIBLE : View.GONE);
        if (count == -1) {
            mMessageCircleTip.setText("");
        } else {
            mMessageCircleTip.setText(count >= 1000 ? "999+" : count + "");
        }
    }

    @Override
    protected void initView(View rootView) {
        mIvIcon = (ImageView) rootView.findViewById(R.id.iv_icon);
        mTvText = (TextView) rootView.findViewById(R.id.tv_title);
        mMessageCircleTip = (MessageCircle) rootView.findViewById(R.id.mc_circle);
    }

    public void setTextColor(int textColor, int selectedTextColor) {
        mTextColor = textColor;
        mSelectedTextColor = selectedTextColor;

        mTvText.setTextColor(mTextColor);
    }

    public void setText(String text) {
        mTvText.setText(text);
    }

    public void setIconImage(int iconImage, int selectedIconImage) {
        mSelectedIconImage = selectedIconImage;
        mIconImage = iconImage;

        mIvIcon.setImageResource(iconImage);
    }
}

它繼承了AbsTab類,重寫AbsTab中的抽象方法,getTab方法就是返回一個(gè)AbsTab的子類,這個(gè)子類需要開發(fā)者去創(chuàng)建

還有setAdapter方法邏輯也做了修改,修改最大的地方就是TabHost中的addTabs方法,V1.0版本中添加Tab是創(chuàng)建一個(gè)Tab類,而現(xiàn)在是通過適配器的getTab方法獲得AbsTab類,然后添加AbsTab到TabHost當(dāng)中。

總結(jié)

到此V2.0中修改的類和業(yè)務(wù)邏輯就都講完了;開發(fā)中如果需要定制Tab UI, 首先新建一個(gè)繼承自AbsTab的Tab類(項(xiàng)目中我默認(rèn)實(shí)現(xiàn)了一個(gè)DefaultTab), 在新建的Tab類中創(chuàng)建UI布局, 給布局添加數(shù)據(jù), 設(shè)置布局選中和不選中的UI樣式, 然后新建一個(gè)繼承自BaseAdapter 的適配器類, 重寫getTab方法返回一個(gè)AbsTab類,就是剛創(chuàng)建的繼承自AbsTab的Tab類,然后調(diào)用setAdapter的方法即可。

完整代碼:https://github.com/chenpengfei88/TabContainerView/tree/v2.0
歡迎大家Star,F(xiàn)ollow,謝謝。

最后編輯于
?著作權(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)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

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