iOS的客户端菜单功能仿百度糯米/美团二级菜单

我刚好最近在开发一个商城项目,实现了一个简单的控件,就和大家一起分享一下。

控件的效果就是类似百度糯米或者美团的二级菜单,我开发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
*/
@Override
public 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
*/
@Override
public 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);
}
}
/***
* 弹出框关闭
*/
@Override
public 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 row
public int item; //right row
public 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() {
@Override
public 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);
}
@Override
public 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);
}
@Override
public 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; //key
public 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

以上所述是小编给大家介绍的iOS的客户端菜单功能仿百度糯米/美团二级菜单,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对我们网站的支持!

(0)

相关推荐

  • Android仿美团下拉菜单(商品选购)实例代码

    美团电商应用平台大家使用非常频繁,下面小编通过本文给大家介绍电商应用平台中常用的选择类别下拉列表的实现.先给大家展示下效果图: 一.下拉列表的实现 其实实现方法有很多,这时实现的也没有什么技术含量,只是总结下自己在项目中的做法,也提供一个思路. 首先是列表的数据,一般数据都是从后台读过来,这里因为没有后台,所以写死在客户端: private void initMenuData() { menuData = new ArrayList<map<string, string=""

  • Android仿美团分类下拉菜单实例代码

    本文实例为大家分享了Android仿美团下拉菜单的实现代码,分类进行选择,供大家参考,具体内容如下 效果图 操作平台 AS2.0 第三方框架:butterknife build.gradle dependencies { compile fileTree(dir: 'libs', include: ['*.jar']) testCompile 'junit:junit:4.12' compile 'com.android.support:appcompat-v7:23.4.0' compile

  • iOS的客户端菜单功能仿百度糯米/美团二级菜单

    我刚好最近在开发一个商城项目,实现了一个简单的控件,就和大家一起分享一下. 控件的效果就是类似百度糯米或者美团的二级菜单,我开发iOS的客户端菜单功能,直接参考了git一个项目,对应的UI效果: 其实效果看起来还不错.iOS开发完成以后,又要准备开发Android,发现对应网上的案例还是很少的,或者不是想要的效果.我想参考了别人的项目代码,也为开源项目做点贡献,准备自己开发一个Android的menu项目: 折腾了大概三个小时,终于搞定了,效果如下: 从图片不难看出,这是一个多级菜单,控制者填充

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

    本文实例为大家分享了Android仿QQ分组实现二级菜单展示的具体代码,供大家参考,具体内容如下 首先展示下要实现的效果 动态查看请看链接 1.首先要定义item,也就是二级展示的item child_item.xml <?xml version="1.0" encoding="utf-8"?> <RelativeLayout android:id="@+id/list_friend" xmlns:android="h

  • JS实现的仿东京商城菜单、仿Win右键菜单及仿淘宝TAB特效合集

    本文实例讲述了JS实现的仿东京商城菜单.仿Win右键菜单及仿淘宝TAB特效.分享给大家供大家参考.具体如下: 这是一个非常好的实用菜单整合特效,有多级下拉菜单.仿东京商城的拉出式菜单.仿Windows的右键菜单,仿淘宝的标签Tab菜单,每一个都是精彩,代码中附有丰富的注释,便于你的学习和修改. 运行效果截图如下: 在线演示地址如下: http://demo.jb51.net/js/2015/js-f-jd-taobao-win-rbutton-tab-demo/ 具体代码如下: <!DOCTYP

  • 简单实现js点击展开二级菜单功能

    虽然,jQuery已经非常好用了,但是实际的开发项目中,还是有很多限制,比如项目组奇葩的要求,不能使用任何插件,当然,也是考虑插件占用资源,毕竟100+KB对与小型项目来说还是非常大的.我最近就遇到做个点击展开二级菜单的要求,当然只能用原生的JS去写来实现,我借鉴了网上的一个案例,补充一下,分享一下: 如果,默认打开页面进来时二级菜单是隐藏的,需要点击才能展现二级菜单,再点击就是隐藏二级菜单.这里有两个点,实现展现和隐藏用display="block"和display="no

  • css 二级菜单 实现代码集合 修正版

    css菜单演示 0? " ": "") + "sfhover"; } sfEls[i].onMouseDown=function() { this.className+=(this.className.length>0? " ": "") + "sfhover"; } sfEls[i].onMouseUp=function() { this.className+=(this.cla

  • iOS中仿QQ侧滑菜单功能

    UITabBarController做QQ侧滑菜单效果: 首先要了解UITabBarController的层级结构: UITabBarController加载的其它UIViewController的View都是被添加在UITransitionView上(这是一个私有API),UITransitionView在self.view的0层,UITabBar在的第一层. 所以我的思路是这样的: UITransitionView与UITabBar转移到一个新的View1上去,作为滑动的部分: 在View1

  • 使用Bootrap和Vue实现仿百度搜索功能

    用Vue调用百度的搜索接口,实现简单的搜索功能. 搜索框的样式是基于Bootstrap,当然对样式做了简单的调整, 使之类似于百度搜索.代码如下 <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>百度搜索</title> <style type="text/css"> .gray{ background-color

  • php+ajax实现仿百度查询下拉内容功能示例

    本文实例讲述了php+ajax实现仿百度查询下拉内容功能.分享给大家供大家参考,具体如下: 运行效果如下: html代码: <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Document</title> <script src="https://cdn.bootcss.com/jquer

  • Vue 仿百度搜索功能实现代码

    无上下选择 <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>jsonp</title> <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, us

  • iOS 仿百度外卖-首页重力感应的实例

    今天带来的是仿百度外卖首页的重力感应..(由于只能真机测试,手里测试机只有5s,所以有些地方并没有适配其他机型,需要的还需要根据真机自行适配) 来简单说下实现吧,之前重力感应都是用UIAccelerometer实现的,但是,好像是从iOS 4 以后,这个方法就废弃了,它被直接封装到了CoreMotion框架中,所以现在有关重力感应,加速计什么的都需要通过CoreMotion框架实现,这也算是苹果对于重力感应的整合吧.本文对CoreMotion框架只是进行了简单的使用,想要更深的使用,还是请自行

随机推荐