擴展第三方DropDownMenu v1.5

修改效果

dropdown_demo.gif

解析結(jié)構(gòu)

  • 導(dǎo)讀
    想要擴展首先我需要執(zhí)行下面幾個步驟

1.fork DropDownMenu到自己的github賬號
2.使用 as 的 vcs checkout 出來
3.提交到github
4.發(fā)起 pull request

  • 源碼實現(xiàn)原理
    作者對該控件的分析 導(dǎo)讀
DropDwonMenu 的結(jié)構(gòu).png

這是我對該 DropDownMenu 的組成結(jié)構(gòu)進行的圖解

DropDownMenu :下拉菜單控件 繼承自 LinearLayout
tabMenuView :頂部菜單布局 繼承自 LinearLayout
containerView :底部容器,包含 popupMenuViews , maskView 繼承自 FrameLayout
popupMenuViews :彈出菜單父布局 繼承自 FrameLayout
maskView: 遮罩半透明 View ,點擊可關(guān)閉 DropDownMenu 繼承自 View
contentView :一個頁面除了頂部菜單欄以外的所有內(nèi)容
tabView : ListView → 1 : 1

調(diào)用方法基本解析

DropDownMenu :對 tabMenuView 、 containerView 進行初始化
setDropDownMenu :傳參為 tabTexts (字符串數(shù)組), popupViews ( ListView 數(shù)組), contentView (內(nèi)容 View )。調(diào)用 addtab 方法向 tabMenuView 添加 tabView 并設(shè)置對應(yīng) tabView 點擊切換顯示 ListView
addTab :循環(huán) tabTexts 文本, TextView 賦值添加到 tabMenuView
switchMenu :切換 tab 調(diào)用對應(yīng)的 popupMenuViews 里面的 ListView 顯示,其他的 ListView 隱藏

一般情況下在我們的 UI 圖不是對 tab 特別要求的話,那么這種已經(jīng)符合要求了。但是奈不住它就是不長這樣啊。

  • tabView 樣式擴展
    有時候 UI 圖就是這么可惡,^這個箭頭不是靠右,空的那么開。當然我這里只是舉一個例子。
箭頭居中而不是居最右
  • tabView 功能擴展
    這個需求更加喪心病狂了, tab 不都是下拉框。實現(xiàn)擴展之后可以在 tabMenu 中任意順序插入自定義的 tabView ,且不影響下拉功能。
可以在 tab 位置中插入自己需要的 tabView

代碼實現(xiàn)細則

tabView 樣式擴展源碼實現(xiàn)

這里我們說這個 dropDownMenu 的 tab 為 TextView 肯定無法達到我們想要的效果了。
那么最差將 tab 換成 LinearLayout ,那么自定義效果就隨你自己了。但是我們就這樣實現(xiàn)的話肯定性能跟原來有些差距。那么這個庫 tab 都默認是 viewGroup 多渲染了一層,我們能不能在用的時候,自己定義的 tab_item.xml。 xml 中我們想要 viewGroup 就寫 ViewGroup 包裹,想只要 TextView 就只有 TextView 。
其實我們只需要定義 id 約束, xml 中 TextView 必須指定為(例如)R.id.tv_tab。 DropDownMenu 底層在設(shè)置 tab 的內(nèi)容的時候多一步操作,加載指定的 tab_laytou.xml,然后如果是 ViewGroup 就 findViewById 找到 TextView ,否則就直接轉(zhuǎn)成 TextView 。

1.addTab()方法從代碼中直接 new TextView 改成從 layout 中加載
2.將原來 tabView ( textView )相關(guān)的設(shè)置代碼全部先用獲取 textView 的過濾方法篩選一下 textView

這里只截取關(guān)鍵代碼
原 addTab()

    private void addTab(@NonNull List<String> tabTexts, int i) {
        final TextView tab = new TextView(getContext());
        ...//tab的樣式設(shè)置
        tab.setText(tabTexts.get(i));
        tab.setPadding(dpTpPx(5), dpTpPx(12), dpTpPx(5), dpTpPx(12));
        //添加點擊事件
        ...
        tabMenuView.addView(tab);
        //添加分割線
        ...
    }

改 addTab()

    private void addTab(@NonNull List<String> tabTexts, int i) {
        View tab = inflate(getContext(), R.layout.tab_item, null);
        tab.setLayoutParams(new LayoutParams(0, ViewGroup.LayoutParams.WRAP_CONTENT, 1.0f));
        ...//樣式設(shè)置
        tabMenuView.addView(tab);
        //添加分割線
        ...
    }

增加 tab_item.xml( viewGroup 包含 textView / 只是 textView ) ,樣式的可擴展性大大增強

<!-----------ViewGroup------------------>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="0dp"
    android:layout_height="wrap_content"
    android:layout_weight="1"
    android:gravity="center">

    <TextView
        android:id="@+id/tv_tab"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:drawablePadding="7dp"
        android:gravity="center"
        android:paddingBottom="12dp"
        android:paddingLeft="5dp"
        android:paddingRight="5dp"
        android:paddingTop="12dp"
        android:text="adfad"
        android:textColor="#26a8e0" />
</LinearLayout>
<!-------或者只有TextView,也沒有問題---------------------->
<?xml version="1.0" encoding="utf-8"?>
<TextView android:id="@+id/tv_tab"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:drawablePadding="7dp"
    android:gravity="center"
    android:paddingBottom="12dp"
    android:paddingLeft="5dp"
    android:paddingRight="5dp"
    android:paddingTop="12dp"
    android:textColor="#26a8e0"
    xmlns:android="http://schemas.android.com/apk/res/android" />

過濾獲取 TextView 方法

    /**
     * 獲取tabView中id為tv_tab的textView
     *
     * @param tabView
     * @return
     */
    private TextView getTabTextView(View tabView) {
        TextView tabtext = (TextView) tabView.findViewById(R.id.tv_tab);
        return tabtext;
    }

hint: 然后代碼中凡是涉及到設(shè)置 tab textView 相關(guān)設(shè)置的地方都需要先用我這個方法過濾,替換一下。主要有這么幾個地方,初始化設(shè)置 tab ,選中 List 單項確定設(shè)置 tab ,打開和關(guān)閉菜單對 tab 的文本顏色的設(shè)置。
效果:就是最上面擴展的效果圖
插曲:
應(yīng)趙蘿貝要求加了箭頭在文本的方向?qū)傩?/p>

icon方向?qū)傩?/div>

效果圖

應(yīng)jeff_sun要求添加了可以控制分隔線的高度的屬性

分隔線高度屬性

效果圖

還是這位 jeff_sun (ps: 你們公司 UI 要求真特殊),應(yīng)他的要求為 popupWindows 集合的 view 增加了對 LayoutParams 的支持。
代碼圖

效果圖

tabView 功能擴展源碼實現(xiàn)

從上面可以知道,現(xiàn)在 tabMenuView 的 tab 和 popupMenuViews 的 ListView 的數(shù)量是相同的。而現(xiàn)在我們要實現(xiàn)的是 tabMenuView 中 tab 的數(shù)量> popupMenuViews 的 ListView 的數(shù)量。多的那部分 tabView 就只是展示的功能,不會觸發(fā)點擊下拉展示。
  另外因為 tabtexts 文本是作為數(shù)組順序添加的。所以我們需要用 dropTabViews 類記錄 tabtexts 添加的順序。當點擊了一個 tabView 看是否存在于 dropTabViews 數(shù)組中,不存在就不處理,存在就 indexOf 獲取當前 tabView 在 dropTabViews 中的順序然后去對應(yīng)找 ListView 。這樣處理之后, tabMenuView 設(shè)置 tabtexts 之后就可以隨便在哪個位置上插入需要的 tabView 樣式了,且不影響功能。

1. 創(chuàng)建記錄 tabtexts 順序的而創(chuàng)建的 tabView 數(shù)組
2. 在 switchMenu 切換 popupMenuViews 的 ListView 的獲取方式要過濾一下

舊 switchMenu 方法

   private void switchMenu(View target) {
        System.out.println(current_tab_position);
        for (int i = 0; i < tabMenuView.getChildCount(); i = i + 2) {
            if (target == tabMenuView.getChildAt(i)) {//找到點擊到的tabView
                if (current_tab_position == i) {//點擊的view是原來顯示的tabView則關(guān)閉菜單
                    closeMenu();
                } else {//不是,就顯示菜單
                    if (current_tab_position == -1) {
                        ...
                        popupMenuViews.getChildAt(i / 2).setVisibility(View.VISIBLE);
                    } else {
                        popupMenuViews.getChildAt(i / 2).setVisibility(View.VISIBLE);
                    }
                    ...
                }
            } else {//沒找到就顏色等屬性設(shè)置成普通
                TextView textView = getTabTextView(tabMenuView.getChildAt(i));
                textView.setTextColor(textUnselectedColor);
                textView.setCompoundDrawablesWithIntrinsicBounds(null, null,
                        getResources().getDrawable(menuUnselectedIcon), null);
                popupMenuViews.getChildAt(i / 2).setVisibility(View.GONE);
            }
        }
    }

修改的 switchMenu 方法

 private void switchMenu(View target) {
        for (int i = 0; i < tabMenuView.getChildCount(); i = i + 2) {
            if (target == tabMenuView.getChildAt(i)) {//找到點擊到的tabView
                if (current_tab_position == i) {//點擊的view是原來顯示的tabView則關(guān)閉菜單
                    closeMenu();
                } else {//不是,就顯示菜單
                    ...
                    View listView = getListView(tabMenuView.getChildAt(i));
                    if (listView != null) {
                        listView.setVisibility(View.VISIBLE);
                    }
                    ...
                }
            } else {//沒找到就顏色等屬性設(shè)置成普通
                TextView textView = getTabTextView(tabMenuView.getChildAt(i));
                View listView = getListView(tabMenuView.getChildAt(i));
                if (listView != null) {
                    if(textView!=null){
                        textView.setCompoundDrawablesWithIntrinsicBounds(null, null,
                                getResources().getDrawable(menuUnselectedIcon), null);
                    }
                    listView.setVisibility(View.GONE);
                }
            }
        }
    }

addTab 進一步修改

    private void addTab(@NonNull List<String> tabTexts, int i) {
       ...
        dropTabViews.add(tab);//記錄創(chuàng)建的添加順序
    }

新增 getListView 方法

    /**
     * 獲取dropTabViews中對應(yīng)popupMenuViews數(shù)組中的ListView
     *
     * @param view
     * @return
     */
    private View getListView(View view) {
        if (dropTabViews.contains(view)) {
            int index = dropTabViews.indexOf(view);
            return popupMenuViews.getChildAt(index);
        } else {
            return null;
        }
    }

調(diào)用演示 MainActivity.java

      mDropDownMenu.setDropDownMenu(Arrays.asList(headers), popupViews, contentView);
        //測試tabView擴展功能
        TextView textView= (TextView) getLayoutInflater().inflate(R.layout.tab_text,null);
        textView.setLayoutParams(new LinearLayout.LayoutParams(0, ViewGroup.LayoutParams.WRAP_CONTENT, 1.0f));
        textView.setText("2位置");
        mDropDownMenu.addTab(textView,2);
使用方式

Paste_Image.png

新增tabMenu點擊回調(diào)接口

ItemMenu.png

總結(jié)

樣式性擴展:我們盡量從 xml 中加載 view ,根據(jù)指定 id 獲取控件,到達最大程度的樣式解耦
功能性擴展:將 tabViews 數(shù)組順序的位置不依賴于父 View 的 child ,而是依賴于一個動態(tài)的數(shù)組。我們對父 View 的 child 的添加并不會影響到原來的功能。這樣可以做到 tabView 的功能性擴展

該篇文章代碼在 Github上

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

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

  • 發(fā)現(xiàn) 關(guān)注 消息 iOS 第三方庫、插件、知名博客總結(jié) 作者大灰狼的小綿羊哥哥關(guān)注 2017.06.26 09:4...
    肇東周閱讀 15,019評論 4 61
  • WebSocket-Swift Starscream的使用 WebSocket 是 HTML5 一種新的協(xié)議。它實...
    香橙柚子閱讀 24,694評論 8 183
  • 我叫肖絲絲。 25歲的年紀里, 遇見一個叫何小錦的男人, 還小我兩歲。 我從未試過姐弟戀, 我甚至并不能照顧好自己...
    肖絲絲閱讀 323評論 0 0
  • 01 有趣的靈魂萬里挑一 今天聽老師講寫作課,主題是我特別感興趣的“如何寫出一篇具有吸引力的文章?”說心里話,也許...
    富蘭克劉閱讀 990評論 18 25
  • 大雨 積成了水洼 深一腳 淺一腳 搖搖晃晃向前走著 雨水潑在傘上 散開 慌亂往下爬 有幾滴來不及跑開 從中間掉了下...
    水色森森閱讀 313評論 1 0

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