我们又如何来自定义Menu呢?下面我就主要来讲讲如何在Android上自定义Menu菜单,希望对大家有所帮助。
用过UCWEB-Android版的人都应该对其特殊的menu有印象,把menu做成Tab-Menu(支持分页的Menu),可以容纳比 Android传统的menu更丰富的内容(Android的menu超过6项则缩略在[更多]里),本文参考网上的例子(作 者:CoffeeCole,email:longkefan@foxmail.com),对例子进行简化以及封装,使其作为一个复合控件融入自己的 framework。
先来看看本文程序运行的效果:
TabMenu 本身就是一个PopupWindow,PopupWindow上面放了两个GridView,第一个GridView就是分页标签,位于 PopupWindow的顶部,第二个GridView是菜单,位于PopupWindow的主体。为了实现PopupWindow的弹出/退出的动画效 果,本文使用了以下代码:
在工程的res文件夹里添加anim子目录,再新建文件popup_enter.xml:
1
2
3
4
5
|
<? xml version = "1.0" encoding = "utf-8" ?> < translate android:fromYDelta = "100%p" android:toYDelta = "0" android:duration = "1000" /> < alpha android:fromAlpha = "0.0" android:toAlpha = "1.0" android:duration = "1000" /> </ set > |
新建文件popup_exit.xml:
1
2
3
4
5
|
<? xml version = "1.0" encoding = "utf-8" ?> < translate android:fromYDelta = "0" android:toYDelta = "100%p" android:duration = "1000" /> < alpha android:fromAlpha = "1.0" android:toAlpha = "0.0" android:duration = "1000" /> </ set > |
在工程的values文件夹里新建文件popup_animation.xml:
1
2
3
4
5
6
7
|
<? xml version = "1.0" encoding = "utf-8" ?> < resources > < style name = "PopupAnimation" parent = "android:Animation" > < item name = "android:windowEnterAnimation" >@anim/popup_enter</ item > < item name = "android:windowExitAnimation" >@anim/popup_exit</ item > </ style > </ resources > |
main.xml的源码如下:
1
2
3
4
5
6
7
|
<? xml version = "1.0" encoding = "utf-8" ?> < LinearLayout android:id = "@+id/LinearLayout01" android:layout_width = "fill_parent" android:layout_height = "fill_parent" < TextView android:id = "@+id/TextView01" android:layout_height = "wrap_content" android:layout_width = "fill_parent" android:text = "扩展Menu----hellogv" ></ TextView > </ LinearLayout > |
TabMenu的封装类TabMenu.java的源码如下:
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
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
|
package com.testTabMenu; import android.content.Context; import android.graphics.Color; import android.graphics.drawable.ColorDrawable; import android.view.Gravity; import android.view.View; import android.view.ViewGroup; import android.widget.BaseAdapter; import android.widget.GridView; import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.PopupWindow; import android.widget.TextView; import android.widget.AdapterView.OnItemClickListener; import android.widget.LinearLayout.LayoutParams; public class TabMenu extends PopupWindow{ private GridView gvBody, gvTitle; private LinearLayout mLayout; private MenuTitleAdapter titleAdapter; public TabMenu(Context context,OnItemClickListener titleClick,OnItemClickListener bodyClick, MenuTitleAdapter titleAdapter, int colorBgTabMenu, int aniTabMenu){ super (context); mLayout = new LinearLayout(context); mLayout.setOrientation(LinearLayout.VERTICAL); //标题选项栏 gvTitle = new GridView(context); gvTitle.setLayoutParams( new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT)); gvTitle.setNumColumns(titleAdapter.getCount()); gvTitle.setStretchMode(GridView.STRETCH_COLUMN_WIDTH); gvTitle.setVerticalSpacing( 1 ); gvTitle.setHorizontalSpacing( 1 ); gvTitle.setGravity(Gravity.CENTER); gvTitle.setOnItemClickListener(titleClick); gvTitle.setAdapter(titleAdapter); gvTitle.setSelector( new ColorDrawable(Color.TRANSPARENT)); //选中的时候为透明色 this .titleAdapter=titleAdapter; //子选项栏 gvBody = new GridView(context); gvBody.setLayoutParams( new LayoutParams(LayoutParams.FILL_PARENT,LayoutParams.WRAP_CONTENT)); gvBody.setSelector( new ColorDrawable(Color.TRANSPARENT)); //选中的时候为透明色 gvBody.setNumColumns( 4 ); gvBody.setStretchMode(GridView.STRETCH_COLUMN_WIDTH); gvBody.setVerticalSpacing( 10 ); gvBody.setHorizontalSpacing( 10 ); gvBody.setPadding( 10 , 10 , 10 , 10 ); gvBody.setGravity(Gravity.CENTER); gvBody.setOnItemClickListener(bodyClick); mLayout.addView(gvTitle); mLayout.addView(gvBody); //设置默认项 this .setContentView(mLayout); this .setWidth(LayoutParams.FILL_PARENT); this .setHeight(LayoutParams.WRAP_CONTENT); this .setBackgroundDrawable( new ColorDrawable(colorBgTabMenu)); // 设置TabMenu菜单背景 this .setAnimationStyle(aniTabMenu); this .setFocusable( true ); // menu菜单获得焦点 如果没有获得焦点menu菜单中的控件事件无法响应 } public void SetTitleSelect( int index) { gvTitle.setSelection(index); this .titleAdapter.SetFocus(index); } public void SetBodySelect( int index, int colorSelBody) { int count=gvBody.getChildCount(); for ( int i= 0 ;i<count;i++) { if (i!=index) ((LinearLayout)gvBody.getChildAt(i)).setBackgroundColor(Color.TRANSPARENT); } ((LinearLayout)gvBody.getChildAt(index)).setBackgroundColor(colorSelBody); } public void SetBodyAdapter(MenuBodyAdapter bodyAdapter) { gvBody.setAdapter(bodyAdapter); } /** * 自定义Adapter,TabMenu的每个分页的主体 * */ static public class MenuBodyAdapter extends BaseAdapter { private Context mContext; private int fontColor,fontSize; private String[] texts; private int [] resID; /** * 设置TabMenu的分页主体 * @param context 调用方的上下文 * @param texts 按钮集合的字符串数组 * @param resID 按钮集合的图标资源数组 * @param fontSize 按钮字体大小 * @param color 按钮字体颜色 */ public MenuBodyAdapter(Context context, String[] texts, int [] resID, int fontSize, int fontColor) { this .mContext = context; this .fontColor = fontColor; this .texts = texts; this .fontSize=fontSize; this .resID=resID; } public int getCount() { return texts.length; } public Object getItem( int position) { return makeMenyBody(position); } public long getItemId( int position) { return position; } private LinearLayout makeMenyBody( int position) { LinearLayout result= new LinearLayout( this .mContext); result.setOrientation(LinearLayout.VERTICAL); result.setGravity(Gravity.CENTER_HORIZONTAL|Gravity.CENTER_VERTICAL); result.setPadding( 10 , 10 , 10 , 10 ); TextView text = new TextView( this .mContext); text.setText(texts[position]); text.setTextSize(fontSize); text.setTextColor(fontColor); text.setGravity(Gravity.CENTER); text.setPadding( 5 , 5 , 5 , 5 ); ImageView img= new ImageView( this .mContext); img.setBackgroundResource(resID[position]); result.addView(img, new LinearLayout.LayoutParams( new LayoutParams(LayoutParams.WRAP_CONTENT,LayoutParams.WRAP_CONTENT))); result.addView(text); return result; } public View getView( int position, View convertView, ViewGroup parent) { return makeMenyBody(position); } } /** * 自定义Adapter,TabMenu的分页标签部分 * */ static public class MenuTitleAdapter extends BaseAdapter { private Context mContext; private int fontColor,unselcolor,selcolor; private TextView[] title; /** * 设置TabMenu的title * @param context 调用方的上下文 * @param titles 分页标签的字符串数组 * @param fontSize 字体大小 * @param fontcolor 字体颜色 * @param unselcolor 未选中项的背景色 * @param selcolor 选中项的背景色 */ public MenuTitleAdapter(Context context, String[] titles, int fontSize, int fontcolor, int unselcolor, int selcolor) { this .mContext = context; this .fontColor = fontcolor; this .unselcolor = unselcolor; this .selcolor=selcolor; this .title = new TextView[titles.length]; for ( int i = 0 ; i < titles.length; i++) { title[i] = new TextView(mContext); title[i].setText(titles[i]); title[i].setTextSize(fontSize); title[i].setTextColor(fontColor); title[i].setGravity(Gravity.CENTER); title[i].setPadding( 10 , 10 , 10 , 10 ); } } public int getCount() { return title.length; } public Object getItem( int position) { return title[position]; } public long getItemId( int position) { return title[position].getId(); } /** * 设置选中的效果 */ private void SetFocus( int index) { for ( int i= 0 ;i<title.length;i++) { if (i!=index) { title[i].setBackgroundDrawable( new ColorDrawable(unselcolor)); //设置没选中的颜色 title[i].setTextColor(fontColor); //设置没选中项的字体颜色 } } title[index].setBackgroundColor( 0x00 ); //设置选中项的颜色 title[index].setTextColor(selcolor); //设置选中项的字体颜色 } public View getView( int position, View convertView, ViewGroup parent) { View v; if (convertView == null ) { v = title[position]; } else { v = convertView; } return v; } } } |
testTabMenu介绍了数据的定义以及TabMenu的使用,源码如下:
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
|
package com.testTabMenu; import android.app.Activity; import android.graphics.Color; import android.os.Bundle; import android.view.Gravity; import android.view.Menu; import android.view.View; import android.widget.AdapterView; import android.widget.AdapterView.OnItemClickListener; import android.widget.Toast; public class testTabMenu extends Activity { TabMenu.MenuBodyAdapter []bodyAdapter= new TabMenu.MenuBodyAdapter[ 3 ]; TabMenu.MenuTitleAdapter titleAdapter; TabMenu tabMenu; int selTitle= 0 ; @Override public void onCreate(Bundle savedInstanceState) { super .onCreate(savedInstanceState); setContentView(R.layout.main); //设置分页栏的标题 titleAdapter = new TabMenu.MenuTitleAdapter( this , new String[] { "常用" , "设置" , "工具" }, 16 , 0xFF222222 ,Color.LTGRAY,Color.WHITE); //定义每项分页栏的内容 bodyAdapter[ 0 ]= new TabMenu.MenuBodyAdapter( this , new String[] { "常用1" , "常用2" , }, new int [] { R.drawable.menu_test, R.drawable.menu_bookmark}, 13 , 0xFFFFFFFF ); bodyAdapter[ 1 ]= new TabMenu.MenuBodyAdapter( this , new String[] { "设置1" , "设置2" , "设置3" }, new int [] { R.drawable.menu_edit, R.drawable.menu_delete, R.drawable.menu_fullscreen}, 13 , 0xFFFFFFFF ); bodyAdapter[ 2 ]= new TabMenu.MenuBodyAdapter( this , new String[] { "工具1" , "工具2" , "工具3" , "工具4" }, new int [] { R.drawable.menu_copy, R.drawable.menu_cut, R.drawable.menu_normalmode, R.drawable.menu_quit }, 13 , 0xFFFFFFFF ); tabMenu= new TabMenu( this , new TitleClickEvent(), new BodyClickEvent(), titleAdapter, 0x55123456 , //TabMenu的背景颜色 R.style.PopupAnimation); //出现与消失的动画 tabMenu.update(); tabMenu.SetTitleSelect( 0 ); tabMenu.SetBodyAdapter(bodyAdapter[ 0 ]); } class TitleClickEvent implements OnItemClickListener{ @Override public void onItemClick(AdapterView<?> arg0, View arg1, int arg2, long arg3) { selTitle=arg2; tabMenu.SetTitleSelect(arg2); tabMenu.SetBodyAdapter(bodyAdapter[arg2]); } } class BodyClickEvent implements OnItemClickListener{ @Override public void onItemClick(AdapterView<?> arg0, View arg1, int arg2, long arg3) { tabMenu.SetBodySelect(arg2,Color.GRAY); String str= "第" +String.valueOf(selTitle)+ "栏/n/r" + "第" +String.valueOf(arg2)+ "项" ; Toast.makeText(testTabMenu. this , str, 500 ).show(); } } @Override /** * 创建MENU */ public boolean onCreateOptionsMenu(Menu menu) { menu.add( "menu" ); // 必须创建一项 return super .onCreateOptionsMenu(menu); } @Override /** * 拦截MENU */ public boolean onMenuOpened( int featureId, Menu menu) { if (tabMenu != null ) { if (tabMenu.isShowing()) tabMenu.dismiss(); else { tabMenu.showAtLocation(findViewById(R.id.LinearLayout01), Gravity.BOTTOM, 0 , 0 ); } } return false ; // 返回为true 则显示系统menu } } |
这样,我们就基本实现了Android自定义Menu菜单的功能,谢谢阅读!