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>
结束
- ok,做到这,就大功告成了,具体的代码还是以我的Demo为主
- 如果需要源码,关注微信公共号:AppCode,回复关键字“筛选菜单”,即可拿到源码下载的链接
apk下载
点击下载demo的apk
如果这篇文章对你有用,欢迎关注我们的微信公共号:AppCode
扫描下面二维码即可关注
- Android最牛逼的多条件筛选菜单
- Android最牛逼的多条件筛选菜单
- android 多条件筛选菜单效果
- Android常见多条件筛选菜单(美团、58)
- Android常见多条件筛选菜单(美团、58)
- Android高阶UI之一个实用的多条件筛选菜单
- 安卓实现多下拉筛选多条件筛选菜单多级筛选菜单
- 自己造轮子--android常用多条件筛选菜单实现思路(类似美团,爱奇艺电影票下拉菜单)
- android筛选菜单实现
- Android仿美团筛选菜单
- Android 菜单筛选器
- 一个实用的多条件筛选菜单,在很多App上都能看到这个效果,如美团,爱奇艺电影票等.
- 用phpcms做多种条件筛选菜单
- php多条件筛选
- 多条件筛选
- zTree的菜单筛选
- Android三级联动筛选菜单
- android 下拉筛选菜单 view的显示和隐藏动画
- Android Studio 打包jar,aar
- 删除文件和文件夹
- BaseServlet
- Linux如此“自私”?
- 前十大编程语言你会几种?
- Android最牛逼的多条件筛选菜单
- C 指针常识的小结
- 14.TabHosty以及RadioGroup实现微博主页面切换
- 【linux】常用Linux命令小合集(一)
- elasticsearch2.3.5启用search guard2后logstash的配置
- 15.Progress和title_bar的样式文件引入别的layout
- iPhone 7的音频革命:Lightning真的会取代3.5mm音频接口吗?
- 如何实现超高写多读少并发的无锁缓存
- Android设计模式2之Template Method