1. 程式人生 > >Android最牛逼的多條件篩選選單

Android最牛逼的多條件篩選選單

說明

本來很懶,但是還是會忍不住的寫下這有用既沒有用的所謂技術部落格,希望會給你帶來有所啟發,因為這樣的功能,寫的人很多,也是為了自己能夠理解的夠透徹,也是為了大家也能更好的理解吧,其實自定義控制元件,也就是那麼回事,沒有什麼可難的,好吧,可能是這個太簡單了。
這是58,趕集都用到的控制元件,這樣的控制元件,自定義起來其實也並不難,自己專案當中用到了這個,於是就研究了一番,可能在你的專案當中也有可能會遇到這樣的需求,正好,也可以來研究下,說真的,今天你見到的這個效果,比58,和趕集做的效果 要好多了,他們做的真的很low。

效果展示

先來看下他長什麼樣子吧

效果

對,就是這個樣子,今天我們就來看看到底是怎麼做出來的。

思路

整體的所有佈局都是用程式碼創建出來的,不是寫死在佈局檔案裡的,這樣會更靈活

  • 建立選單欄,就是地址呀,年齡,性別的佈局,水平的LinearLayout
  • 向選單欄裡添加布局,就是一個簡單的TextView,和分割線,然後將該佈局新增至父控制元件中,就是最外層佈局
  • 建立下劃線,再新增至父控制元件中
  • 建立內容顯示區,注意,內容顯示區包括上圖中的顯示的內容(這裡是內容區域),還有點選下拉選單出來的佈局,和半透明的背景,都是在內容區的,他的佈局是FrameLayout,注意FrameLayout的特點,有不熟悉他的特點的可以先查一下他的特點,這樣就會更好的理解這個控制元件的繪製了。
  • 內容顯示區為FrameLayout,他裡面包括3部分,最裡層是真正的的內容顯示區,就是上圖中看到的文字(這裡是內容區域),中間層是半透明區域,就是大家看到的變暗的背景,最外層是點選下拉選單之後彈出來的內容

程式碼實現

下面將會帶你用程式碼我做這個控制元件的思路

  public class DropDownMenu extends LinearLayout {

    //頂部選單佈局
    private LinearLayout tabMenuView;
    //底部容器,包含popupMenuViews,maskView
    private FrameLayout containerView;
    //彈出選單父佈局
    private FrameLayout popupMenuViews;
    //遮罩半透明View,點選可關閉DropDownMenu
    private View maskView;
    //tabMenuView裡面選中的tab位置,-1表示未選中
private int current_tab_position = -1; //分割線顏色 private int dividerColor = 0xffcccccc; //tab選中顏色 private int textSelectedColor = 0xff890c85; //tab未選中顏色 private int textUnselectedColor = 0xff111111; //遮罩顏色 private int maskColor = 0x88888888; //tab字型大小 private int menuTextSize = 14; //tab選中圖示 private int menuSelectedIcon; //tab未選中圖示 private int menuUnselectedIcon; public DropDownMenu(Context context) { super(context, null); } public DropDownMenu(Context context, AttributeSet attrs) { this(context, attrs, 0); } public DropDownMenu(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); setOrientation(VERTICAL); //為DropDownMenu新增自定義屬性 int menuBackgroundColor = 0xffffffff; int underlineColor = 0xffcccccc; TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.DropDownMenu); underlineColor = a.getColor(R.styleable.DropDownMenu_underlineColor, underlineColor); dividerColor = a.getColor(R.styleable.DropDownMenu_dividerColor, dividerColor); textSelectedColor = a.getColor(R.styleable.DropDownMenu_textSelectedColor, textSelectedColor); textUnselectedColor = a.getColor(R.styleable.DropDownMenu_textUnselectedColor, textUnselectedColor); menuBackgroundColor = a.getColor(R.styleable.DropDownMenu_menuBackgroundColor, menuBackgroundColor); maskColor = a.getColor(R.styleable.DropDownMenu_maskColor, maskColor); menuTextSize = a.getDimensionPixelSize(R.styleable.DropDownMenu_menuTextSize, menuTextSize); menuSelectedIcon = a.getResourceId(R.styleable.DropDownMenu_menuSelectedIcon, menuSelectedIcon); menuUnselectedIcon = a.getResourceId(R.styleable.DropDownMenu_menuUnselectedIcon, menuUnselectedIcon); a.recycle(); //初始化tabMenuView並新增到tabMenuView tabMenuView = new LinearLayout(context); LayoutParams params = new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT); tabMenuView.setOrientation(HORIZONTAL); tabMenuView.setBackgroundColor(menuBackgroundColor); tabMenuView.setLayoutParams(params); addView(tabMenuView, 0); //為tabMenuView新增下劃線 View underLine = new View(getContext()); underLine.setLayoutParams(new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, dpTpPx(1.0f))); underLine.setBackgroundColor(underlineColor); addView(underLine, 1); //初始化containerView並將其新增到DropDownMenu containerView = new FrameLayout(context); containerView.setLayoutParams(new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.MATCH_PARENT)); addView(containerView, 2); } }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81

注意下面的成員變數

private LinearLayout tabMenuView;////頂部選單佈局

private FrameLayout containerView;//底部容器,包含popupMenuViews,maskView(暗色背景)

private FrameLayout popupMenuViews;//彈出選單父佈局

private View maskView;//遮罩半透明View,點選可關閉DropDownMenu

public class DropDownMenu extends LinearLayout {}

也就說整體的佈局是繼承自LinearLayout的

setOrientation(VERTICAL);//在第三個構造方法裡指定了整體佈局的方向

完成了以上步驟,其實大體上的佈局差不多都搭好了,下面就是填充子佈局和資料的問題了

    /**
     * 初始化DropDownMenu
     *
     * @param tabTexts
     * @param popupViews
     * @param contentView
     */
    public void setDropDownMenu(@NonNull List<String> tabTexts, @NonNull List<View> popupViews, @NonNull View contentView) {
        if (tabTexts.size() != popupViews.size()) {
            throw new IllegalArgumentException("params not match, tabTexts.size() should be equal popupViews.size()");
        }

        for (int i = 0; i < tabTexts.size(); i++) {
            addTab(tabTexts, i);
        }
        containerView.addView(contentView, 0);

        maskView = new View(getContext());
        maskView.setLayoutParams(new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.MATCH_PARENT));
        maskView.setBackgroundColor(maskColor);
        maskView.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                closeMenu();
            }
        });
        containerView.addView(maskView, 1);
        maskView.setVisibility(GONE);

        popupMenuViews = new FrameLayout(getContext());
        popupMenuViews.setVisibility(GONE);
        containerView.addView(popupMenuViews, 2);

        for (int i = 0; i < popupViews.size(); i++) {
            popupViews.get(i).setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT));
            popupMenuViews.addView(popupViews.get(i), i);
        }

    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39

這一步是對外暴露的方法,專門給選單欄,填充資料,還有為內容區填充佈局的,佈局可以填充任何佈局,很靈活

addTab(tabTexts, i);這個方法,下面會給出程式碼,用來給選單欄添加布局和選單欄的分割線的

containerView.addView(contentView, 0);//將傳入的內容佈局新增到內容區(預設是顯示的)

containerView.addView(maskView, 1);//新增暗色背景(預設是GONG的)

containerView.addView(popupMenuViews, 2);//將點選選單欄後顯示的佈局,注意,這個佈局裡也有子佈局,那就是listview,所以現在是講父佈局新增到內容區的(預設是GONG的)

popupMenuViews.addView(popupViews.get(i), i);//這一步才是為點選選單欄後顯示的佈局填充子佈局的,也就是listview

  private void addTab(@NonNull List<String> tabTexts, int i) {
        final TextView tab = new TextView(getContext());
        tab.setSingleLine();
        tab.setEllipsize(TextUtils.TruncateAt.END);
        tab.setGravity(Gravity.CENTER);
        tab.setTextSize(TypedValue.COMPLEX_UNIT_PX, menuTextSize);
        tab.setLayoutParams(new LayoutParams(0, ViewGroup.LayoutParams.WRAP_CONTENT, 1.0f));
        tab.setTextColor(textUnselectedColor);
        tab.setCompoundDrawablesWithIntrinsicBounds(null, null, null, getResources().getDrawable(menuUnselectedIcon));
        tab.setText(tabTexts.get(i));
        tab.setPadding(dpTpPx(5), dpTpPx(12), dpTpPx(5), dpTpPx(12));
        //新增點選事件
        tab.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {

                switchMenu(tab);
            }
        });
        tabMenuView.addView(tab);
        //新增分割線
        if (i < tabTexts.size() - 1) {
            View view = new View(getContext());
            LayoutParams layoutParams = new LayoutParams(dpTpPx(0.5f), dpTpPx(25));
            layoutParams.gravity = Gravity.CENTER_VERTICAL;
            view.setLayoutParams(layoutParams);
            view.setBackgroundColor(dividerColor);
            tabMenuView.addView(view);
        }
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30

這一步是為選單欄添加布局,和分割線的,還有為選單欄新增點選事件,沒有什麼可說的

     /**
     * 切換選單
     *
     * @param view
     */
    private void switchMenu(View view) {

        for (int i = 0; i < tabMenuView.getChildCount(); i = i + 2) {

            if (view == tabMenuView.getChildAt(i)) {
                if (current_tab_position == i) {
                    closeMenu();
                } else {
                    if (current_tab_position == -1) {
                        popupMenuViews.setVisibility(View.VISIBLE);
                        popupMenuViews.setAnimation(AnimationUtils.loadAnimation(getContext(), R.anim.dd_menu_in));
                        maskView.setVisibility(VISIBLE);
                        maskView.setAnimation(AnimationUtils.loadAnimation(getContext(), R.anim.dd_mask_in));
                        popupMenuViews.getChildAt(i / 2).setVisibility(View.VISIBLE);
                    } else {
                        popupMenuViews.getChildAt(i / 2).setVisibility(View.VISIBLE);
                    }
                    current_tab_position = i;
                    ((TextView) tabMenuView.getChildAt(i)).setTextColor(textSelectedColor);
                    ((TextView) tabMenuView.getChildAt(i)).setCompoundDrawablesWithIntrinsicBounds(null, null,
                            null, getResources().getDrawable(menuSelectedIcon));
                }
            } else {
                //設定其他未點選tab的狀態
                ((TextView) tabMenuView.getChildAt(i)).setTextColor(textUnselectedColor);
                ((TextView) tabMenuView.getChildAt(i)).setCompoundDrawablesWithIntrinsicBounds(null, null,
                        null, getResources().getDrawable(menuUnselectedIcon));
                popupMenuViews.getChildAt(i / 2).setVisibility(View.GONE);
            }
        }
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36

這一步是切換選單時要做的,只是改變其他狀態而已

用法

做到這,也就意味著,自定義控制元件寫完了,下面就是如何用他了

佈局

 <example.fussen.dropdownmenu.DropDownMenu xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/dropDownMenu"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    app:dividerColor="@color/blue_app"
    app:maskColor="@color/mask_color"
    app:menuBackgroundColor="@color/base_title_color"
    app:menuSelectedIcon="@drawable/ic_img_up"
    app:menuTextSize="16sp"
    app:menuUnselectedIcon="@drawable/ic_img_down"
    app:textSelectedColor="@color/blue_app"
    app:textUnselectedColor="@color/drop_down_unselected"
    app:underlineColor="@color/blue_app" />

將上面的佈局copy到你的佈局裡就ok啦

自定義的屬性

 <declare-styleable name="DropDownMenu">
    <!--下劃線顏色-->
    <attr name="underlineColor" format="color" />
    <!--分割線顏色(選單欄)-->
    <attr name="dividerColor" format="color" />
    <!--tab選中顏色-->
    <attr name="textSelectedColor" format="color" />
    <!--tab未選中顏色-->
    <attr name="textUnselectedColor" format="color" />
    <!--tab 背景顏色-->
    <attr name="menuBackgroundColor" format="color" />
    <!--遮罩顏色,一般是半透明-->
    <attr name="maskColor" format="color" />
    <!--字型大小-->
    <attr name="menuTextSize" format="dimension" />
    <!--tab選中狀態圖示-->
    <attr name="menuSelectedIcon" format="reference" />
    <!--tab未選中狀態圖示-->
    <attr name="menuUnselectedIcon" format="reference" />
</declare-styleable>

結束

  1. ok,做到這,就大功告成了,具體的程式碼還是以我的Demo為主
  2. 如果需要原始碼,關注微信公共號:AppCode,回覆關鍵字“篩選選單”,即可拿到原始碼下載的連結

apk下載

如果這篇文章對你有用,歡迎關注我們的微信公共號:AppCode

掃描下面二維碼即可關注