Android 多级菜单联动操作
- 今天是分享一个android实现三级菜单联动效果,到了第三级菜单有点复杂,下面带着大家看下代码。
-
项目结构:
-
为了让大家更有的耐心的阅读, 我先从简单的开始说起,我们先看下demo实现的效果吧!这样可以让大家更好的理解后面的思路。
我们来看下整体的布局,主页面无非就只有两个TextView控件,可点击。我把代码贴出来,xml如下:
"http://schemas.android.com/apk/res/android" android:id="@+id/rootview" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> id="@+id/textview1" android:layout_width="fill_parent" android:layout_height="30dp" android:text="Activity Demo" android:textColor="@color/black" android:layout_margin="20dp"/> id="@+id/textview2" android:layout_width="fill_parent" android:layout_height="30dp" android:textColor="@color/black" android:text="Dialog Demo" android:layout_margin="20dp"/>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
然后从Activity Demo进去,我们可以看到先是出来半边的menu列表,效果如下:
这个布局大家都知道,就是一个简单的ListView,以下是code:
<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:background="@color/menudialog_divider_color" android:orientation="vertical"> <ListView android:id="@+id/listview" android:layout_width="fill_parent" android:layout_height="fill_parent" android:background="@color/white" android:cacheColorHint="@android:color/transparent" android:divider="@null" android:scrollbars="none" />LinearLayout>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
那么第二个menu列表是什么出来的呢?布局是一样的,这里三个列表菜单的ListView,我都用同一个xml实现,这并不矛盾,都是ListView列表。这里两个ListView都在同一个屏幕,其实道理很简单,一个ListView占整个屏幕的1/2。第二listView自然可以在同一个屏幕上显示,是不是顿时明白了?哈哈。。。
好,接下来我我们看一下ListView的item布局,代码如下:
<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/menu_item_ly" android:layout_width="match_parent" android:layout_height="wrap_content" android:gravity="center_vertical" android:minHeight="43dp" android:orientation="vertical"> <TextView android:id="@+id/menu_item_textview" android:layout_width="wrap_content" android:layout_height="match_parent" android:layout_marginLeft="16dp" android:layout_weight="1" android:gravity="center_vertical" android:text="title" android:textColor="#000000" android:textSize="17sp"/> <TextView android:id="@+id/menu_item_divider" android:layout_width="match_parent" android:layout_height="1px" android:layout_marginLeft="16dp" android:layout_marginRight="16dp" android:textColor="@color/black" android:background="@color/menudialog_divider_color"/>LinearLayout>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
也很简单,两个TextView控件,第一个是我们要显示的title文本,第二个是title下方的线,以上效果图不太清楚,我这边把颜色加深点,方便大家理解查看。
左右滑动是ViewPager,讲到这里,大致就知道这个结构了,没错,就是在ViewPager里面放入三个ListView,实现三个列表可以左右滑动,我也把这份布局贴出来吧!请看以下:
<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/rootview" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="horizontal"> <com.lai.threemenudemo.view.MyViewPager android:id="@+id/viewpager" android:layout_width="match_parent" android:layout_height="match_parent" android:overScrollMode="never"/>LinearLayout>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
这个ViewPager是自定义的,里面很简单,如下:
package com.lai.threemenudemo.view;import android.content.Context;import android.support.v4.view.ViewPager;import android.util.AttributeSet;/** * Created by LaiYingtang on 2016/5/22. * 主页面左右滑动 */public class MyViewPager extends ViewPager{ public MyViewPager(Context context, AttributeSet attrs) { super(context, attrs); } public MyViewPager(Context context) { super(context); } //判断menu在x,y的位置 public void scrollTo(int x,int y){ if(getAdapter()==null||x>getWidth()*(getAdapter().getCount()-2)){ return; } super.scrollTo(x,y); }}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
以下说重点,我们在第一个ListView中点击某一个item,出来第二个ListView列表,我们是怎么做到的呢?思路跟我们的数据库一样,每个菜单的联动必须要关联另个菜单,这样触动一个item的时候,跟它所关联的item便随之出现,我把这些数据写在一个txt文本里面,我们要读取的时候,直接将这些数据封装到SparseArray集合里面遍历出来即可。这里用到的SparseArray是为了节省内存,提高性能。
我们看下数据是怎么关联起来的,我就不全部贴出来了,贴两个item的数据,后面以此类推。
310000,IT/互联网/软件/通信,0;310100,产品,310000;310101,产品专员/产品助理,310100;310102,产品经理/高级产品经理,310100;310103,产品总监/副总监,310100;310104,产品VP/首席产品官,310100;310105,其他产品类职位,310100;310200,设计,310000;310201,网页设计/网站美工,310200;310202,APP设计,310200;310203,UI/UE/交互设计,310200;310204,Flash/多媒体设计,310200;310205,游戏设计,310200;310206,设计经理/主美,310200;310207,设计总监/副总监,310200;310208,其他设计类职位,310200;
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
我们来看下这些数据到底如何理解,学过mysql的很容易理解,使用id关联数据表的每一个对应的字段,这个也一样,我贴张图讲述就明白了。
看红色框部门,点击左栏产品子菜单,包含了右栏多个item的效果,我们来看下这组数据:
我们可以理解为,在多条数据中,一条数据有三个字段,第一条的titleName为“产品”,用它的id关联了以下多个titleName,得出了产品包含多个item的结果。下面的设计选项也是一样,不妨去试着理解,看如下:
是不是?。。。。。
前面一级菜单到二级菜单也是如此,我们看看效果图:
后面以此类推。结构就这么简单,但是代码有点小复杂。我们一起看看:
这里我贴出dialog这部分的代码,这部分写了注解:
package com.lai.threemenudemo.dialog;import android.content.Context;import android.view.LayoutInflater;import android.view.MotionEvent;import android.view.View;import android.widget.AdapterView;import android.widget.LinearLayout;import android.widget.ListView;import com.lai.threemenudemo.R;import com.lai.threemenudemo.adapter.MenuDialogAdapter;import com.lai.threemenudemo.adapter.MyPagerAdapter;import com.lai.threemenudemo.bean.MenuData;import com.lai.threemenudemo.utils.MenuDataManager;import com.lai.threemenudemo.view.MyViewPager;import java.util.ArrayList;import java.util.List;/** * 三级菜单列表 * Created by LaiYingtang on 2016/5/25. */public class ThreeMenuDialog extends SecondMenuDialog{ private int mWidth; //宽度 private MyViewPager mViewPager; //滑动viewPager private LinearLayout mRootView; //需要显示的layout private View view1,view2,view3; //三个菜单级view private ListView mListView1,mListView2,mListView3; //每个菜单列表都是一个listView private MenuDialogAdapter mListView1Adapter, mListView2Adapter, mListView3Adapter; //列表显示数据必须要的adapter private List views = new ArrayList(); //数据集合 public MenuDataManager mDictDataManager = MenuDataManager.getInstance(); //全部数据 private MenuItemClickListener menuItemClickListener; //接口,点击监听 public ThreeMenuDialog(Context context) { super(context); mWidth = mContext.getResources().getDisplayMetrics().widthPixels;//获取屏幕参数 mContentView = LayoutInflater.from(context).inflate(R.layout.three_menu_dialog,null); //初始化控件及对控件操作 initViews(); setTitle("三级列表");//设置title } private void initViews() { mRootView = (LinearLayout) findViewById(R.id.rootview); mViewPager = (MyViewPager) findViewById(R.id.viewpager); mViewPager.setOffscreenPageLimit(2);//显示2页 //为view加载layout,由于三个级的菜单都是只有一个listView,这里就只xie一个了 LayoutInflater inflater = LayoutInflater.from(mContext); view1 = inflater.inflate(R.layout.pager_number, null); view2 = inflater.inflate(R.layout.pager_number, null); view3 = inflater.inflate(R.layout.pager_number, null); //获取id mListView1 = (ListView) view1.findViewById(R.id.listview); mListView2 = (ListView) view2.findViewById(R.id.listview); mListView3 = (ListView) view3.findViewById(R.id.listview); //获取列表数据了 List list=mDictDataManager.getTripleColumnData(mContext, 0); //关联adapter mListView1Adapter = new MenuDialogAdapter(mContext, list); mListView1Adapter.setSelectedBackgroundResource(R.drawable.select_white);//选中时的背景 mListView1Adapter.setHasDivider(false); mListView1Adapter.setNormalBackgroundResource(R.color.menudialog_bg_gray);//未选中 mListView1.setAdapter(mListView1Adapter); views.add(view1); views.add(view2);//当前是第三级菜单,所以前面已经存在第一,第二菜单了 //关联 mViewPager.setAdapter(new MyPagerAdapter(views)); //触屏监听 mRootView.setOnTouchListener(new View.OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { return mViewPager.dispatchTouchEvent(event); } }); //view1的listView的点击事件 //点击事件 mListView1.setOnItemClickListener(new AdapterView.OnItemClickListener() { @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { if (mListView1Adapter != null) mListView1Adapter.setSelectedPos(position); if (mListView2Adapter != null) mListView2Adapter.setSelectedPos(-1); if (views.contains(view3)) { views.remove(view3); mViewPager.getAdapter().notifyDataSetChanged();//立即更新adapter数据 } MenuData menuData = (MenuData) parent.getItemAtPosition(position);//得到第position个menu子菜单 if (menuData.id == 0) {//不限 if (mListView2Adapter != null) { mListView2Adapter.setData(new ArrayList()); mListView2Adapter.notifyDataSetChanged();//刷新 } setDictItemClickListener(menuData); } else { List list2 = mDictDataManager.getTripleColumnData(mContext, menuData.id); if (mListView2Adapter == null) { mListView2Adapter = new MenuDialogAdapter(mContext, list2); mListView2Adapter.setNormalBackgroundResource(R.color.white); mListView2.setAdapter(mListView2Adapter); } else { mListView2Adapter.setData(list2); mListView2Adapter.notifyDataSetChanged(); } } } }); //view2的listView点击 mListView2.setOnItemClickListener(new AdapterView.OnItemClickListener() { @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { if (mListView2Adapter != null) { mListView2Adapter.setSelectedPos(position); mListView2Adapter.setSelectedBackgroundResource(R.drawable.select_gray); } if (views.contains(view3)) { views.remove(view3); } //从第二级菜单的基础上加载第三级菜单 MenuData menuData = (MenuData) parent.getItemAtPosition(position); List list3 = mDictDataManager.getTripleColumnData(mContext, menuData.id); if (mListView3Adapter == null) { mListView3Adapter = new MenuDialogAdapter(mContext, list3); mListView3Adapter.setHasDivider(false); mListView3Adapter.setNormalBackgroundResource(R.color.menudialog_bg_gray); mListView3.setAdapter(mListView3Adapter); } else { mListView3Adapter.setData(list3); mListView3Adapter.notifyDataSetChanged(); } //放入第三级菜单列表 views.add(view3); mViewPager.getAdapter().notifyDataSetChanged(); if (mViewPager.getCurrentItem() != 1) { mViewPager.postDelayed(new Runnable() { @Override public void run() { mViewPager.setCurrentItem(1);//选一个 } }, 300); } } }); //最后就是第三级菜单的点击了 mListView3.setOnItemClickListener(new AdapterView.OnItemClickListener() { @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { MenuData menuData = (MenuData) parent.getItemAtPosition(position); setDictItemClickListener(menuData);//选中点击的子菜单,去设置titleName } }); } private void setDictItemClickListener(MenuData menuData) { if (menuItemClickListener != null) { menuItemClickListener.onMenuItemClick(menuData); } dismiss(); } public final void setonItemClickListener(MenuItemClickListener listener) { menuItemClickListener = listener; } public interface MenuItemClickListener { public void onMenuItemClick(MenuData menuData); }}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
- 106
- 107
- 108
- 109
- 110
- 111
- 112
- 113
- 114
- 115
- 116
- 117
- 118
- 119
- 120
- 121
- 122
- 123
- 124
- 125
- 126
- 127
- 128
- 129
- 130
- 131
- 132
- 133
- 134
- 135
- 136
- 137
- 138
- 139
- 140
- 141
- 142
- 143
- 144
- 145
- 146
- 147
- 148
- 149
- 150
- 151
- 152
- 153
- 154
- 155
- 156
- 157
- 158
- 159
- 160
- 161
- 162
- 163
- 164
- 165
- 166
- 167
- 168
- 169
- 170
- 171
- 172
- 173
- 174
- 175
- 176
- 177
- 178
- 179
- 180
- 181
- 182
- 183
- 184
- 185
- 186
- 187
- 188
- 189
- 190
然后dialog的动画效果,我也贴出来:
package com.lai.threemenudemo.dialog;import android.app.Dialog;import android.content.Context;import android.view.Gravity;import android.view.View;import android.view.Window;import android.view.WindowManager;import android.widget.LinearLayout;import android.widget.TextView;import com.lai.threemenudemo.R;/** * 菜单动画 * Created by LaiYingtang on 2016/5/25. */public class SecondMenuDialog extends Dialog{ public Context mContext; public LinearLayout containerViewGroup; public View mContentView; public TextView titleView; Window window = null; //构造器 public SecondMenuDialog(Context context) { super(context, R.style.dialog_change_card);//样式 mContext = context; containerViewGroup = (LinearLayout) getLayoutInflater().inflate(R.layout.second_menu_dialog, null); titleView = (TextView) containerViewGroup.findViewById(R.id.dictdialog_title_tv); } public View findViewById(int id) { return mContentView.findViewById(id); } /** * 设置窗口显示 */ public void windowDeploy() { window = getWindow(); // 得到对话框 window.setWindowAnimations(R.style.RegDialogAnimation); // 设置窗口弹出动画效果 WindowManager.LayoutParams windowAttributes = window.getAttributes(); windowAttributes.x = 0; // x小于0左移,大于0右移 windowAttributes.y = 0; // y小于0上移,大于0下移 windowAttributes.height = 2 * mContext.getResources().getDisplayMetrics().heightPixels / 3; windowAttributes.width = LinearLayout.LayoutParams.FILL_PARENT; windowAttributes.alpha = 0.6f; //设置透明度 windowAttributes.gravity = Gravity.BOTTOM; // 设置重力,对齐方式 window.setAttributes(windowAttributes); } //显示到layout里面 @Override public void show() { if (mContentView != null) { containerViewGroup.addView(mContentView); } setContentView(containerViewGroup); setCanceledOnTouchOutside(true); windowDeploy(); super.show(); } //选中的title设置为title @Override public void setTitle(CharSequence title) { if (titleView != null) titleView.setText(title); }}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
有一些注释提示大家去理解,我在这里也不能全部讲的那么详细,重要的是,还是要靠大家自己去理解,去参悟,这样才能真正学到东西。好了,大家自己慢慢去消化吧!最后我还是会把源码链接给共享出来,希望大家看了后对你们有所帮助,谢谢!
最后我附上demo的链接:
源码下载
更多相关文章
- Android魔术(第五弹)—— 一步步实现滑动折叠列表
- Android 弧形列表转盘的实现(三),View跟随RecyclerView做旋转动画;
- android列表收缩与展开仿QQ好友列表(非常详细,附源码)
- adb shell 命令详解 在Android中查看和管理sqlite数据库
- Android 数据库SQLite升级降级
- Android学习路线(二十六)Android数据存储
- Android中如何解析JSON数据