iOS的客户端菜单功能仿百度糯米/美团二级菜单
程序员文章站
2023-12-19 12:20:10
我刚好最近在开发一个商城项目,实现了一个简单的控件,就和大家一起分享一下。
控件的效果就是类似百度糯米或者美团的二级菜单,我开发ios的客户端菜单功能,直接参考了git一...
我刚好最近在开发一个商城项目,实现了一个简单的控件,就和大家一起分享一下。
控件的效果就是类似百度糯米或者美团的二级菜单,我开发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的客户端菜单功能仿百度糯米/美团二级菜单,希望对大家有所帮助