Android最牛逼的多条件筛选菜单

来源:互联网 发布:重庆大学网络客户端 编辑:程序博客网 时间:2024/04/30 00:32

说明


本来很懒,但是还是会忍不住的写下这有用既没有用的所谓技术博客,希望会给你带来有所启发,因为这样的功能,写的人很多,也是为了自己能够理解的够透彻,也是为了大家也能更好的理解吧,其实自定义控件,也就是那么回事,没有什么可难的,好吧,可能是这个太简单了。
这是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);    }  }

注意下面的成员变量

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);        }    }

这一步是对外暴露的方法,专门给菜单栏,填充数据,还有为内容区填充布局的,布局可以填充任何布局,很灵活

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);        }    }

这一步是为菜单栏添加布局,和分割线的,还有为菜单栏添加点击事件,没有什么可说的

     /**     * 切换菜单     *     * @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);            }        }    }

这一步是切换菜单时要做的,只是改变其他状态而已

用法


做到这,也就意味着,自定义控件写完了,下面就是如何用他了

布局

 <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下载

点击下载demo的apk

如果这篇文章对你有用,欢迎关注我们的微信公共号:AppCode

扫描下面二维码即可关注

3 1