我剛好最近在開發一個商城項目,實現了一個簡單的控件,就和大家一起分享一下。
控件的效果就是類似百度糯米或者美團的二級菜單,我開發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的客戶端菜單功能仿百度糯米/美團二級菜單,希望對大家有所幫助,如果大家有任何疑問請給我留言,小編會及時回復大家的。在此也非常感謝大家對本站網站的支持!