DropDownMenu仿美团等下拉菜单源码分析

来源:互联网 发布:linux mv 目录非空 编辑:程序博客网 时间:2024/05/12 06:51

前言

最近项目中用到了,多条件可选搜索,因此用到了下拉菜单,效果如下图:
效果图
这是一个第三方的控件,在此向作者致敬。项目地址:
https://github.com/dongjunkun/DropDownMenu
作者关于项目的介绍:自己造轮子–android常用多条件筛选菜单实现思路(类似美团,爱奇艺电影票下拉菜单)
之所以将这个自定义控件贴出来,是感觉作者分析问题的能力很强,解决问题的方法也比较巧妙。

源码分析

先分析一下这个视图层级:

层级分析
这个自定义控件难度不大,但是却很巧妙。弄懂了视图的层级也就搞懂了这个控件的原理。
顶层的菜单布局比较简单,就是一个线性水平布局。
通过对顶层的菜单布局的tab设置点击事件,来决定下方containerView这个FrameLayout布局的显示。

上源码

package com.yyydjk.library;import android.content.Context;import android.content.res.TypedArray;import android.support.annotation.NonNull;import android.text.TextUtils;import android.util.AttributeSet;import android.util.DisplayMetrics;import android.util.TypedValue;import android.view.Gravity;import android.view.View;import android.view.ViewGroup;import android.view.animation.AnimationUtils;import android.widget.FrameLayout;import android.widget.LinearLayout;import android.widget.TextView;import java.util.List;/** * Created by dongjunkun on 2015/6/17. */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_ddunderlineColor, underlineColor);        dividerColor = a.getColor(R.styleable.DropDownMenu_dddividerColor, dividerColor);        textSelectedColor = a.getColor(R.styleable.DropDownMenu_ddtextSelectedColor, textSelectedColor);        textUnselectedColor = a.getColor(R.styleable.DropDownMenu_ddtextUnselectedColor, textUnselectedColor);        menuBackgroundColor = a.getColor(R.styleable.DropDownMenu_ddmenuBackgroundColor, menuBackgroundColor);        maskColor = a.getColor(R.styleable.DropDownMenu_ddmaskColor, maskColor);        menuTextSize = a.getDimensionPixelSize(R.styleable.DropDownMenu_ddmenuTextSize, menuTextSize);        menuSelectedIcon = a.getResourceId(R.styleable.DropDownMenu_ddmenuSelectedIcon, menuSelectedIcon);        menuUnselectedIcon = a.getResourceId(R.styleable.DropDownMenu_ddmenuUnselectedIcon, 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);    }    /**     * 初始化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);        }    }    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, getResources().getDrawable(menuUnselectedIcon), null);        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());            view.setLayoutParams(new LayoutParams(dpTpPx(0.5f), ViewGroup.LayoutParams.MATCH_PARENT));            view.setBackgroundColor(dividerColor);            tabMenuView.addView(view);        }    }    /**     * 改变tab文字     *     * @param text     */    public void setTabText(String text) {        if (current_tab_position != -1) {            ((TextView) tabMenuView.getChildAt(current_tab_position)).setText(text);        }    }    public void setTabClickable(boolean clickable) {        for (int i = 0; i < tabMenuView.getChildCount(); i = i + 2) {            tabMenuView.getChildAt(i).setClickable(clickable);        }    }    /**     * 关闭菜单     */    public void closeMenu() {        if (current_tab_position != -1) {            ((TextView) tabMenuView.getChildAt(current_tab_position)).setTextColor(textUnselectedColor);            ((TextView) tabMenuView.getChildAt(current_tab_position)).setCompoundDrawablesWithIntrinsicBounds(null, null,                    getResources().getDrawable(menuUnselectedIcon), null);            popupMenuViews.setVisibility(View.GONE);            popupMenuViews.setAnimation(AnimationUtils.loadAnimation(getContext(), R.anim.dd_menu_out));            maskView.setVisibility(GONE);            maskView.setAnimation(AnimationUtils.loadAnimation(getContext(), R.anim.dd_mask_out));            current_tab_position = -1;        }    }    /**     * DropDownMenu是否处于可见状态     *     * @return     */    public boolean isShowing() {        return current_tab_position != -1;    }    /**     * 切换菜单     *     * @param target     */    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)) {                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,                            getResources().getDrawable(menuSelectedIcon), null);                }            } else {                ((TextView) tabMenuView.getChildAt(i)).setTextColor(textUnselectedColor);                ((TextView) tabMenuView.getChildAt(i)).setCompoundDrawablesWithIntrinsicBounds(null, null,                        getResources().getDrawable(menuUnselectedIcon), null);                popupMenuViews.getChildAt(i / 2).setVisibility(View.GONE);            }        }    }    public int dpTpPx(float value) {        DisplayMetrics dm = getResources().getDisplayMetrics();        return (int) (TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, value, dm) + 0.5);    }}
1 0