前言
最近项目中用到了,多条件可选搜索,因此用到了下拉菜单,效果如下图:
这是一个第三方的控件,在此向作者致敬。项目地址:
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 = -;
//分割线颜色
private int dividerColor = ;
//tab选中颜色
private int textSelectedColor = ;
//tab未选中颜色
private int textUnselectedColor = ;
//遮罩颜色
private int maskColor = ;
//tab字体大小
private int menuTextSize = ;
//tab选中图标
private int menuSelectedIcon;
//tab未选中图标
private int menuUnselectedIcon;
public DropDownMenu(Context context) {
super(context, null);
}
public DropDownMenu(Context context, AttributeSet attrs) {
this(context, attrs, );
}
public DropDownMenu(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
setOrientation(VERTICAL);
//为DropDownMenu添加自定义属性
int menuBackgroundColor = ;
int underlineColor = ;
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, );
//为tabMenuView添加下划线
View underLine = new View(getContext());
underLine.setLayoutParams(new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, dpTpPx(f)));
underLine.setBackgroundColor(underlineColor);
addView(underLine, );
//初始化containerView并将其添加到DropDownMenu
containerView = new FrameLayout(context);
containerView.setLayoutParams(new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.MATCH_PARENT));
addView(containerView, );
}
/**
* 初始化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 = ; i < tabTexts.size(); i++) {
addTab(tabTexts, i);
}
containerView.addView(contentView, );
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, );
maskView.setVisibility(GONE);
popupMenuViews = new FrameLayout(getContext());
popupMenuViews.setVisibility(GONE);
containerView.addView(popupMenuViews, );
for (int i = ; 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(, ViewGroup.LayoutParams.WRAP_CONTENT, f));
tab.setTextColor(textUnselectedColor);
tab.setCompoundDrawablesWithIntrinsicBounds(null, null, getResources().getDrawable(menuUnselectedIcon), null);
tab.setText(tabTexts.get(i));
tab.setPadding(dpTpPx(), dpTpPx(), dpTpPx(), dpTpPx());
//添加点击事件
tab.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
switchMenu(tab);
}
});
tabMenuView.addView(tab);
//添加分割线
if (i < tabTexts.size() - ) {
View view = new View(getContext());
view.setLayoutParams(new LayoutParams(dpTpPx(f), ViewGroup.LayoutParams.MATCH_PARENT));
view.setBackgroundColor(dividerColor);
tabMenuView.addView(view);
}
}
/**
* 改变tab文字
*
* @param text
*/
public void setTabText(String text) {
if (current_tab_position != -) {
((TextView) tabMenuView.getChildAt(current_tab_position)).setText(text);
}
}
public void setTabClickable(boolean clickable) {
for (int i = ; i < tabMenuView.getChildCount(); i = i + ) {
tabMenuView.getChildAt(i).setClickable(clickable);
}
}
/**
* 关闭菜单
*/
public void closeMenu() {
if (current_tab_position != -) {
((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 = -;
}
}
/**
* DropDownMenu是否处于可见状态
*
* @return
*/
public boolean isShowing() {
return current_tab_position != -;
}
/**
* 切换菜单
*
* @param target
*/
private void switchMenu(View target) {
System.out.println(current_tab_position);
for (int i = ; i < tabMenuView.getChildCount(); i = i + ) {
if (target == tabMenuView.getChildAt(i)) {
if (current_tab_position == i) {
closeMenu();
} else {
if (current_tab_position == -) {
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 / ).setVisibility(View.VISIBLE);
} else {
popupMenuViews.getChildAt(i / ).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 / ).setVisibility(View.GONE);
}
}
}
public int dpTpPx(float value) {
DisplayMetrics dm = getResources().getDisplayMetrics();
return (int) (TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, value, dm) + );
}
}