好久没有打开我的CSDN博客了,也是因为年龄一年年大了,生活压力大了,思考的事情已经不在项目上了,最近看见有人给我csdn上留言,说我好久没有更新CSDN了,我刚好最近在开发一个商城项目,实现了一个简单的控件,就和大家一起分享一下。
控件的效果就是类似百度糯米或者美团的二级菜单,我开发iOS的客户端菜单功能,直接参考了git一个项目,对应的UI效果:

其实效果看起来还不错。iOS开发完成以后,又要准备开发Android,发现对应网上的案例还是很少的,或者不是想要的效果。我想参考了别人的项目代码,也为开源项目做点贡献,准备自己开发一个Android的menu项目;
折腾了大概三个小时,终于搞定了,效果如下:

从图片不难看出,这是一个多级菜单,控制者填充数据源,所以实现的时候,尽量封装的使用,使用者最好是能两三行代码搞定。

具体实现思路:
1、MenuView,实现了第一级菜单的封装

①、view初始化和数据源定义;

②、绘制一级菜单;

③、控制子菜单的PopupWindow弹出框
代码具体如下:

package com.spring.sky.menuproject.view;import android.content.Context;
import android.util.AttributeSet;
import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup;
import android.widget.LinearLayout;
import android.widget.TextView;import com.spring.sky.menuproject.AppInfoUtils;
import com.spring.sky.menuproject.R;import java.util.List;/*** Created by springsky on 16/10/24.*/public class MenuView extends LinearLayout implements View.OnClickListener, MenuPopupWindow.OnMenuListener {private String[] hintTexts;public List[] dataSource;public TextView[] textViews;private int textColor = R.color.gray_80;private int textColorSelected = R.color.orange;private int textSize;private int lineHeight ;private MenuPopupWindow menuPopupWindow;private OnMenuListener onMenuListener;View lineView;TextView lastTv;private IndexPath[] indexPaths;public MenuView(Context context) {super(context);init(context);}public MenuView(Context context, AttributeSet attrs) {super(context, attrs);init(context);}public MenuView(Context context, AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);init(context);}public void setHintTexts(String[] hintTexts) {this.hintTexts = hintTexts;}public void setDataSource(List[] dataSource) {this.dataSource = dataSource;reloadData();}/**** 设置当前选中的数据* @param indexPath*/public void setIndexPath(IndexPath indexPath) {setIndexPath(indexPath, false);}/**** 设置当前选中的内容* @param indexPath* @param actionMenu 是否通知监听器*/public void setIndexPath(IndexPath indexPath, boolean actionMenu) {indexPaths[indexPath.column] = indexPath;if (actionMenu) {TextView lastTv = textViews[indexPath.column];List<MenuModel> list = dataSource[indexPath.column];if(list == null || indexPath.row >= list.size()){return;}MenuModel left = list.get(indexPath.row);MenuModel menuModel = null;if (indexPath.item < 0) {menuModel = left;} else {MenuModel right = left.chindMenu.get(indexPath.item);menuModel = right;}lastTv.setText(menuModel.value);if (onMenuListener != null) {onMenuListener.onMenu(indexPath, menuModel);}}}public List[] getDataSource() {return dataSource;}/**** 初始化* @param context*/private void init(Context context) {menuPopupWindow = new MenuPopupWindow(context);menuPopupWindow.setOnMenuListener(this);AppInfoUtils.getViewHeight(this);textSize = AppInfoUtils.spToPx(6);lineHeight = AppInfoUtils.dipToPx(1);}/**** 绘制一级菜单分类*/private void reloadData() {removeAllViews();if (dataSource == null || dataSource.length < 1) {return;}int count = dataSource.length;int height = getMeasuredHeight() - lineHeight;setOrientation(LinearLayout.VERTICAL);LinearLayout menuBaseView = new LinearLayout(getContext());menuBaseView.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, height));menuBaseView.setWeightSum(count);menuBaseView.setGravity(Gravity.CENTER);menuBaseView.setOrientation(LinearLayout.HORIZONTAL);indexPaths = new IndexPath[count];textViews = new TextView[count];for (int i = 0; i < count; i++) {indexPaths[i] = new IndexPath(i, 0, -1);LinearLayout tempBaseView = new LinearLayout(getContext());tempBaseView.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, height, 1));tempBaseView.setGravity(Gravity.CENTER);TextView tv = new TextView(getContext());tv.setTextColor(getResources().getColor(textColor));tv.setTextSize(textSize);LinearLayout.LayoutParams params = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.MATCH_PARENT);tv.setGravity(Gravity.CENTER);tv.setLayoutParams(params);tv.setMaxLines(1);tv.setCompoundDrawablesWithIntrinsicBounds(0, 0, R.mipmap.triangle_down, 0);tv.setCompoundDrawablePadding(AppInfoUtils.dipToPx(2));tv.setId(i);tv.setOnClickListener(this);textViews[i] = tv;tempBaseView.addView(tv);menuBaseView.addView(tempBaseView);if (hintTexts != null && i < hintTexts.length) {tv.setText(hintTexts[i]);}View lineView = new View(getContext());lineView.setBackgroundColor(getResources().getColor(R.color.main_bg_in));menuBaseView.addView(lineView, new LayoutParams(AppInfoUtils.dipToPx(1), height - AppInfoUtils.dipToPx(8)));}addView(menuBaseView);lineView = new View(getContext());lineView.setBackgroundColor(getResources().getColor(R.color.main_bg_in));addView(lineView, new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, lineHeight));}/**** 一级菜单点击事件触发* @param v*/@Overridepublic void onClick(View v) {lastTv = (TextView) v;int column = v.getId();List<MenuModel> list = dataSource[column];lastTv.setCompoundDrawablesWithIntrinsicBounds(0, 0, R.mipmap.triangle_up, 0);lastTv.setTextColor(getResources().getColor(textColorSelected));menuPopupWindow.setLeftList(column, list);IndexPath indexPath = indexPaths[column];menuPopupWindow.setSelect(indexPath.row, indexPath.item);
//        int[] location = new int[2];
//        lineView.getLocationOnScreen(location);menuPopupWindow.showAsDropDown(lineView);
//        menuPopupWindow.showAtLocation(this,Gravity.BOTTOM,0,0);}/**** 弹出框点击事件处理* @param column* @param row* @param item* @param menuModel*/@Overridepublic void onMenu(int column, int row, int item, MenuModel menuModel) {TextView lastTv = textViews[column];lastTv.setText(menuModel.value);IndexPath indexPath = indexPaths[column];indexPath.row = row;indexPath.item = item;onMenuDismiss();if (onMenuListener != null) {onMenuListener.onMenu(indexPath, menuModel);}}/**** 弹出框关闭*/@Overridepublic void onMenuDismiss() {lastTv.setTextColor(getResources().getColor(R.color.gray_80));lastTv.setCompoundDrawablesWithIntrinsicBounds(0, 0, R.mipmap.triangle_down, 0);}/**** 设置监听器* @param onMenuListener*/public void setOnMenuListener(OnMenuListener onMenuListener) {this.onMenuListener = onMenuListener;}public static interface OnMenuListener {void onMenu(IndexPath indexPath, MenuModel menuModel);}/***** 菜单列、行、二级子行*/public static class IndexPath {public int column; //一级菜单public int row; //left rowpublic int item; //right rowpublic IndexPath(int column, int row, int item) {this.column = column;this.row = row;this.item = item;}}
}

2、PopupWIndow主要是实现了弹出框显示子列的一级和二级菜单的数据。

我使用了两个ListView来动态实现数据的加载。

具体代码如下:

package com.spring.sky.menuproject.view;import android.content.Context;
import android.graphics.drawable.PaintDrawable;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.widget.AdapterView;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.PopupWindow;import com.spring.sky.menuproject.R;import java.util.List;/*** Created by springsky on 16/10/20.*/public class MenuPopupWindow extends PopupWindow implements AdapterView.OnItemClickListener {Context mContext;private ListView leftLv,rightLv;private OnMenuListener onMenuListener;private List<MenuModel> leftList,rightList;private MenuAdapter menuLeftAdapter,menuRightAdapter;private int column;boolean hasSecond;/**** 初始化* @param context*/public MenuPopupWindow(Context context){this.mContext = context;View view = LayoutInflater.from(mContext).inflate(R.layout.menu_popup_window, null);leftLv = (ListView) view.findViewById(R.id.leftLv);leftLv.setChoiceMode(ListView.CHOICE_MODE_SINGLE);rightLv = (ListView) view.findViewById(R.id.rightLv);rightLv.setChoiceMode(ListView.CHOICE_MODE_SINGLE);setContentView(view);setBackgroundDrawable(new PaintDrawable());setFocusable(true);setWidth(ViewGroup.LayoutParams.MATCH_PARENT);setHeight(LinearLayout.LayoutParams.WRAP_CONTENT);setOnDismissListener(new PopupWindow.OnDismissListener() {@Overridepublic void onDismiss() { leftLv.setSelection(0);rightLv.setSelection(0);if( onMenuListener != null ){onMenuListener.onMenuDismiss();}}});menuLeftAdapter = new MenuAdapter(mContext);menuLeftAdapter.setColumn(0);menuLeftAdapter.setList(leftList);leftLv.setAdapter(menuLeftAdapter);leftLv.setOnItemClickListener(this);menuRightAdapter = new MenuAdapter(mContext);menuRightAdapter.setColumn(1);menuRightAdapter.setList(rightList);rightLv.setAdapter(menuRightAdapter);rightLv.setOnItemClickListener(this);}@Overridepublic void showAsDropDown(View anchor) {super.showAsDropDown(anchor);}/**** 加载数据* @param column* @param leftList*/public void setLeftList(int column,List<MenuModel> leftList) {this.column = column;this.leftList = leftList;hasSecond = false;for (MenuModel childModel : leftList){if(childModel.hasChind()){hasSecond = true;break;}}menuLeftAdapter.setList(leftList);if(!hasSecond){rightLv.setVisibility(View.GONE);setRightList(null);}else {rightLv.setVisibility(View.VISIBLE);}}/**** 默认选中的一级和二级行* @param row* @param item*/public void setSelect(int row,int item){if(row < 0 || leftList == null || row >= leftList.size()){return;}MenuModel leftModel = leftList.get(row);leftLv.setSelection(row);menuLeftAdapter.setSelectPosition(row);setRightList(leftModel.chindMenu);if(item < 0 || rightList ==null || item >= rightList.size()){return;}rightLv.setSelection(item);menuRightAdapter.setSelectPosition(item);}private void setRightList(List<MenuModel> rightList) {this.rightList = rightList;menuRightAdapter.setList(rightList);}@Overridepublic void onItemClick(AdapterView<?> parent, View view, int position, long id) {if(parent.getId() == leftLv.getId()){MenuModel model = leftList.get(position);if(leftLv.getSelectedItemPosition() == position){return;}if(model.hasChind()){menuLeftAdapter.setSelectPosition(position);setRightList(model.chindMenu);}else {dismiss();}onMenuClick(position,0,model);}else {menuRightAdapter.setSelectPosition(position);MenuModel model = rightList.get(position);onMenuClick(menuLeftAdapter.getSelectPosition(),position,model);dismiss();}}void onMenuClick(int row,int item,MenuModel model){if(onMenuListener != null){onMenuListener.onMenu(column,row,item,model);}}public void setOnMenuListener(OnMenuListener onMenuListener) {this.onMenuListener = onMenuListener;}public static interface OnMenuListener{void onMenu(int column, int row, int item, MenuModel menuModel);void onMenuDismiss();}}

3、其他的就是MenuModel,考虑是多级层次关系,所以建议使用链结构。

package com.spring.sky.menuproject.view;import java.util.List;/*** Created by springsky on 16/10/20.*/public class MenuModel {public Object key; //keypublic String value; //显示的内容public List<MenuModel> chindMenu; //子列表数据public MenuModel(){super();}public MenuModel(Object key, String value, List<MenuModel> chindMenu){super();this.key = key;this.value = value;this.chindMenu = chindMenu;}/**** 是否有子列表数据* @return*/public boolean hasChind(){return (chindMenu != null && chindMenu.size() > 0);}
}

诶,生活压力大了,也不会写博客了,就简单描述一下,希望大家不要见怪。
项目的源码,我已经提交到git上了。
下载地址:https://github.com/skyfouk/AndroidMenuProject.git

希望大家继续完善

仿百度糯米/美团二级菜单相关推荐

  1. 仿美团列表android,android 仿美团二级菜单

    [实例简介] [实例截图] [核心代码] package com.example.meituandemo; import java.util.ArrayList; import com.example ...

  2. Android 实现仿QQ分组实现二级菜单展示

    首先展示下要实现的效果 动态查看请看链接https://recordit.co/GHjVH9WMz6 1.首先要定义item,也就是二级展示的item child_item.xml <?xml ...

  3. 仿百度的下拉菜单原生js

    废话不多说直接上demo 登录 微博登录 百度登录 网易登录 设置 微博登录 百度登录 网易登录 学术 微博登录 百度登录 网易登录 js如下:注释的是最不用动脑子的想法:没有注释就涉及到闭包的问题, ...

  4. php实现多商家开发,Thinkphp5.0实战-仿百度糯米开发多商家电商平台学习注意事项...

    小伙伴们在学习本课程的时候需要关注下以下内容,现将一些课程相关的注意事项总结如下: 一.框架版本导致的问题汇总 1.4.1节 前端模块页面搭建 中07:31处的 STATIC 如果您的框架是最新的框架 ...

  5. php仿幕课网,Thinkphp5.0实战-仿百度糯米开发多商家电商平台学习注意事项

    小伙伴们在学习本课程的时候需要关注下以下内容,现将一些课程相关的注意事项总结如下: 一.框架版本导致的问题汇总 1.4.1节 前端模块页面搭建 中07:31处的 STATIC 如果您的框架是最新的框架 ...

  6. 【ExpandTabView】Android 仿大众,美团下拉菜单ExpandTabView

    原文地址:https://github.com/yueyueniao2012/ExpandTabView 参考地址:http://blog.csdn.net/minimicall/article/de ...

  7. html 仿百度百科导航下拉菜单

    演示图1 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3 ...

  8. 仿美团外卖菜单界面的实现

    仿美团外卖菜单界面的实现 布局文件 总布局 <?xml version="1.0" encoding="utf-8"?> <LinearLay ...

  9. Android仿ios二级菜单侧滑,仿IOS的列表项滑动菜单——ListItemMenu

    一个简单的仿IOS的列表项滑动菜单(也不知道怎么描述比较好). 顺手做出来的小东西,就分享给大家了. 仿iOS列表项滑动菜单: 1.滑动出现菜单,越界阻尼效果: 2.删除列表项效果. GitHub地址 ...

最新文章

  1. 陆奇“入驻” YC,开启新征程
  2. R函数:交集intersect、并集union、找不同setdiff、判断相同setequal
  3. 11、流程控制语句详解,IF,CASE,LOOP,LEAVE, ITERATE,REPEAT,WHILE
  4. yarn RM crash问题一例
  5. hdu 4027(线段树)
  6. map容器实现一对多
  7. 竟然如此简单!C++实现完全随机加密、解析库,并附上完整代码分析
  8. jQuery基础部分笔记
  9. linux .i文件,Linux的文件I/O
  10. 不显示删除回复显示所有回复显示星级回复显示得分回复 由于扩展配置问题而无法提供您请求的页面。如果该页面是脚本,请添加处理程序。...
  11. 使用cmd命令创建vue(ivieiw)项目
  12. IntelliJ IDEA 2017 汉化包及教程
  13. 使用clusterProfiler进行KEGG富集分析
  14. python从srt文件中只提取歌词
  15. 时间轮 (史上最全)
  16. iphone5信号无服务器,iPhone手机信号这么强,原因是开启了“它”,果粉:有救了...
  17. 卸载chrome浏览器_如何在Chrome,Firefox和其他浏览器中卸载扩展程序
  18. React 18的基本使用
  19. java 方麦子_南方麦子什么时候成熟?小麦有什么营养价值呢?
  20. 公众号接口消息推送+VB+WebService实战

热门文章

  1. matlab下载安装及永久激活教程(解决安装失败并不断提示激活问题)
  2. 火山引擎项亮揭秘字节跳动基于 HPC 的大规模机器学习技术|直播分享报名
  3. 抖音sdk调用,关注与取消关注抖音号
  4. 进程/线程/协程的区别
  5. 怎样将word中的图片另存为jpg格式的图片
  6. BZOJ 2959 长跑 LCT+动态边双
  7. 用Ps制作网页原版总结
  8. 如何用java调用 Python开发的算法模型
  9. 怎么使用PDF编辑软件,如何旋转PDF文件页面方向
  10. 无线网络优化目标及内容介绍