我刚好最近在开发一个商城项目,实现了一个简单的控件,就和大家一起分享一下。
控件的效果就是类似百度糯米或者美团的二级菜单,我开发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;
}
}
}










