DropDownMenu仿美团等下拉菜单源码分析
程序开发
2023-09-21 09:09:17
前言
最近项目中用到了,多条件可选搜索,因此用到了下拉菜单,效果如下图:
这是一个第三方的控件,在此向作者致敬。项目地址:
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,maskViewprivate FrameLayout containerView;//弹出菜单父布局private FrameLayout popupMenuViews;//遮罩半透明View,点击可关闭DropDownMenuprivate 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并添加到tabMenuViewtabMenuView = 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并将其添加到DropDownMenucontainerView = 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 tabTexts, @NonNull List 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() {@Overridepublic 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 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() {@Overridepublic 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);}
}
标签:
上一篇:
JS 之 验证日期格式
下一篇:
相关文章
-
无相关信息