处女男学Android(十二)---Android 菜单(Menu)详解与应用
一、前言
转载请标明出处:http://blog.csdn.net/wlwlwlwl015/article/details/42170771
本篇blog将记录一下Android中菜单的使用方法,虽然在新版本中推荐使用ActionBar去替代菜单,但我认为菜单依然是挺不错的一种UI交互组件,比ActionBar好点一些,对于手指不灵活的人比起来ActionBar右上角的那个方块小按钮,或许ta会更喜欢Menu呢,废话不多说,下面就具体介绍一下Android中关于Menu的使用方法。
二、创建第一个菜单
菜单有两种创建方式,分别是:
- 通过Java代码创建菜单对象。
- 通过xml资源文件定义菜单。
这里我想也不必多说,肯定应该选择第二种形式,在Activity中写代码去创建菜单必然导致程序代码过于臃肿,而且也不易查看和维护,而第二种方法既容易观察菜单的结构,也降低了耦合性,下面是官方给出的将“Using a menu resource”作为最佳实践的理由,简单看一下:
所以我这里就不浪费篇幅去记录“通过代码去创建菜单”了,主要记录一下如何通过xml文件定义菜单资源以及如何在Activity中引用并设置以及使用菜单。
菜单的资源文件通常应该放在/res/menu目录下,菜单资源的根元素通常是<menu.../>元素,并且它不需要指定任何属性,仅是菜单资源文件的根标签而已。我们在eclipse中新建一个Android工程,在/res/menu下去new一个Menu Resource,可以看到Menu的基本结构:
可以看到<menu.../>元素内可包含的子元素:
- <group></group>
- <item/>
<?xml version="1.0" encoding="utf-8"?> <menu xmlns:android="http://schemas.android.com/apk/res/android" > <item android:id="@+id/item_1" android:title="title1"/> <item android:id="@+id/item_2" android:title="title2"/> <item android:id="@+id/item_3" android:title="title3"/> <item android:id="@+id/item_4" android:title="title4"/> <item android:id="@+id/item_5" android:title="title5"/> <item android:id="@+id/item_6" android:title="title6"/> </menu>
写好了资源文件之后,在Activity中需要重写onCreateOptionsMenu去加载菜单,加载方式也很简单,通过MenuInflater的inflate方法即可加载菜单,完全类似于我们LayoutInflater的用法。关于菜单Item的点击事件需要在Activity中重写onOptionsItemSelected,根据回调参数来判断不同的Item从而进行不同的处理,其实这些在新建Activity之后都会自动生成的,下面贴上这两个方法的代码,很简单:
@Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.my_menu, menu); return true; } @Override public boolean onOptionsItemSelected(MenuItem item) { // Handle action bar item clicks here. The action bar will // automatically handle clicks on the Home/Up button, so long // as you specify a parent activity in AndroidManifest.xml. int id = item.getItemId(); switch (id) { case R.id.item_1: Toast.makeText(this, "item_1 has been clicked!", Toast.LENGTH_SHORT) .show(); ; break; case R.id.item_2: Toast.makeText(this, "item_2 has been clicked!", Toast.LENGTH_SHORT) .show(); break; case R.id.item_3: Toast.makeText(this, "item_3 has been clicked!", Toast.LENGTH_SHORT) .show(); break; case R.id.item_4: Toast.makeText(this, "item_4 has been clicked!", Toast.LENGTH_SHORT) .show(); break; case R.id.item_5: Toast.makeText(this, "item_5 has been clicked!", Toast.LENGTH_SHORT) .show(); break; case R.id.item_6: Toast.makeText(this, "item_6 has been clicked!", Toast.LENGTH_SHORT) .show(); break; } return true; }最后看一下运行效果:
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); ListView lv = (ListView) findViewById(R.id.lv_test); registerForContextMenu(lv); //为上下文菜单注册一个ListView }下面看一下接下来的需要做的事情,文档中也已经说的很清楚了:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" > <ScrollView android:id="@+id/sv_4lv" android:layout_width="match_parent" android:layout_height="match_parent" > <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" > <LinearLayout android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="1" android:background="@drawable/top_part" > </LinearLayout> <com.wl.view.MyListView android:id="@+id/lv_test" android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="2" android:entries="@array/hero" > </com.wl.view.MyListView> </LinearLayout> </ScrollView> </LinearLayout>
menu的布局文件也很简单:
<?xml version="1.0" encoding="utf-8"?> <menu xmlns:android="http://schemas.android.com/apk/res/android" > <item android:id="@+id/item1" android:title="新窗口打开"/> <item android:id="@+id/item2" android:title="后台打开"/> <item android:id="@+id/item3" android:title="选择文本"/> <item android:id="@+id/item4" android:title="复制链接地址"/> <item android:id="@+id/item5" android:title="下载链接"/> </menu>
最后是Activity代码:
package com.wl.contextmenudemo; import android.app.Activity; import android.content.Context; import android.os.Bundle; import android.view.ContextMenu; import android.view.ContextMenu.ContextMenuInfo; import android.view.LayoutInflater; import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; import android.widget.BaseAdapter; import android.widget.ListView; import android.widget.ScrollView; import android.widget.TextView; import android.widget.Toast; import com.wl.model.BaiduItem; import com.wl.view.MyListView; public class MainActivity extends Activity { private BaiduItem baiduItem; private Context context; private LayoutInflater inflater; private ScrollView sv; private MyListView mlv; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); context = this; inflater = LayoutInflater.from(context); sv = (ScrollView) findViewById(R.id.sv_4lv); sv.smoothScrollTo(0, 0); MyListView lv = (MyListView) findViewById(R.id.lv_test); baiduItem = new BaiduItem(); lv.setAdapter(new Myadapter()); registerForContextMenu(lv); // 为上下文菜单注册一个ListView } @Override public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) { // TODO Auto-generated method stub getMenuInflater().inflate(R.menu.my_menu_2, menu); } @Override public boolean onContextItemSelected(MenuItem item) { // TODO Auto-generated method stub switch (item.getItemId()) { case R.id.item1: Toast.makeText(context, "新窗口打开!", Toast.LENGTH_SHORT).show(); break; case R.id.item2: Toast.makeText(context, "后台打开!", Toast.LENGTH_SHORT).show(); break; case R.id.item3: Toast.makeText(context, "选择文本!", Toast.LENGTH_SHORT).show(); break; case R.id.item4: Toast.makeText(context, "复制链接地址!", Toast.LENGTH_SHORT).show(); break; case R.id.item5: Toast.makeText(context, "下载链接!", Toast.LENGTH_SHORT).show(); break; } return true; } @Override public boolean onCreateOptionsMenu(Menu menu) { // TODO Auto-generated method stub return super.onCreateOptionsMenu(menu); } class Myadapter extends BaseAdapter { @Override public int getCount() { // TODO Auto-generated method stub return baiduItem.items.size(); } @Override public Object getItem(int position) { // TODO Auto-generated method stub return baiduItem.items.get(position); } @Override public long getItemId(int position) { // TODO Auto-generated method stub return position; } @Override public View getView(int position, View convertView, ViewGroup parent) { // TODO Auto-generated method stub View v = inflater.inflate(R.layout.my_item_1, null); TextView title = (TextView) v.findViewById(R.id.tv_title); title.setText(baiduItem.items.get(position).getTitle()); TextView content = (TextView) v.findViewById(R.id.tv_content); content.setText(baiduItem.items.get(position).getContent()); TextView url = (TextView) v.findViewById(R.id.tv_url); url.setText(baiduItem.items.get(position).getUrlAndDate()); return v; } }; }
代码中通过自定义ListView来处理和ScrollView滑动冲突,关于数据则通过封装好的BaiduItem这个类直接提供,数据的初始化写在这个类的静态代码块中,由于只有5条数据,所以adapter也没有用ViewHolder优化,整体很简单,只是模仿那个百度的效果装个B,重点还是理解一下context menu的适用场合,最后看一下运行效果图:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" > <LinearLayout android:id="@+id/ll_top_bar" android:layout_width="match_parent" android:layout_height="wrap_content" android:background="#000" android:orientation="horizontal" android:padding="8dp" > <TextView android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="3" android:text="我不是微信" android:textColor="#ccc" android:textSize="16sp" /> <LinearLayout android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" > <ImageButton android:id="@+id/ibtn_search" android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="@drawable/ic_search" /> <ImageButton android:id="@+id/ibtn_add" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginLeft="20dp" android:background="@drawable/ic_add" /> </LinearLayout> </LinearLayout> </LinearLayout>
Activity代码:
package com.wl.menusdemo; import android.app.Activity; import android.content.Context; import android.os.Bundle; import android.view.KeyEvent; import android.view.MenuItem; import android.view.View; import android.view.View.OnClickListener; import android.widget.ImageButton; import android.widget.PopupMenu; import android.widget.Toast; public class MainActivity extends Activity implements OnClickListener { private ImageButton ibtnAdd; private ImageButton ibtnSearch; private PopupMenu popMenu; private Context context; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); context = this; ibtnAdd = (ImageButton) findViewById(R.id.ibtn_add); ibtnAdd.setOnClickListener(this); ibtnSearch = (ImageButton) findViewById(R.id.ibtn_search); } @Override public void onClick(View v) { // TODO Auto-generated method stub if (v == ibtnAdd) { popMenu = new PopupMenu(context, ibtnAdd); getMenuInflater().inflate(R.menu.pop_menu, popMenu.getMenu()); popMenu.show(); popMenu.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() { @Override public boolean onMenuItemClick(MenuItem item) { // TODO Auto-generated method stub switch (item.getItemId()) { case R.id.item_chart: Toast.makeText(context, "发起群聊!", Toast.LENGTH_SHORT) .show(); break; case R.id.item_add_friend: Toast.makeText(context, "添加朋友!", Toast.LENGTH_SHORT) .show(); break; case R.id.item_sao: Toast.makeText(context, "扫一扫!", Toast.LENGTH_SHORT) .show(); break; case R.id.item_idea: Toast.makeText(context, "意见反馈!", Toast.LENGTH_SHORT) .show(); break; } return false; } }); } } }
package com.wl.menusdemo; import android.app.Activity; import android.content.Context; import android.os.Bundle; import android.view.KeyEvent; import android.widget.Toast; public class SecondActivity extends Activity { private Context context; @Override protected void onCreate(Bundle savedInstanceState) { // TODO Auto-generated method stub super.onCreate(savedInstanceState); setContentView(R.layout.second); context = this; } @Override public boolean onKeyDown(int keyCode, KeyEvent event) { // TODO Auto-generated method stub if (keyCode == KeyEvent.KEYCODE_MENU) { Toast.makeText(context, "准备好,要弹出菜单了!", Toast.LENGTH_LONG).show(); } return true; } }
<?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:orientation="vertical" > <Button android:id="@+id/btn_ver_update" android:layout_width="match_parent" android:layout_height="wrap_content" android:background="@drawable/my_btn_selector_2" android:gravity="center" android:padding="5dp" android:text="版本更新" android:textColor="#62A6E7" android:textSize="20sp" /> <LinearLayout android:layout_width="match_parent" android:layout_height="2dp" android:background="#ccc" > </LinearLayout> <Button android:id="@+id/btn_help" android:layout_width="match_parent" android:layout_height="wrap_content" android:background="@drawable/my_btn_selector_3" android:gravity="center" android:padding="5dp" android:text="帮助与反馈" android:textColor="#62A6E7" android:textSize="20sp" /> <LinearLayout android:layout_width="match_parent" android:layout_height="2dp" android:background="#ccc" > </LinearLayout> <Button android:id="@+id/btn_exit_qq" android:layout_width="match_parent" android:layout_height="wrap_content" android:background="@drawable/my_btn_selector_4" android:gravity="center" android:padding="5dp" android:text="退出QQ" android:textColor="#62A6E7" android:textSize="20sp" /> <Button android:id="@+id/btn_undo" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginBottom="8dp" android:layout_marginTop="8dp" android:background="@drawable/my_btn_selector" android:gravity="center" android:padding="5dp" android:text="取消" android:textColor="#62A6E7" android:textSize="20sp" /> </LinearLayout>
Activity:
package com.wl.menusdemo; import android.app.ActionBar.LayoutParams; import android.app.Activity; import android.content.Context; import android.os.Bundle; import android.util.DisplayMetrics; import android.view.KeyEvent; import android.view.LayoutInflater; import android.view.View; import android.view.View.OnClickListener; import android.view.WindowManager; import android.widget.Button; import android.widget.PopupWindow; import android.widget.PopupWindow.OnDismissListener; import android.widget.Toast; public class SecondActivity extends Activity implements OnClickListener { private Context context; private PopupWindow popupWindow; @Override protected void onCreate(Bundle savedInstanceState) { // TODO Auto-generated method stub super.onCreate(savedInstanceState); setContentView(R.layout.second); context = this; } @Override public boolean onKeyDown(int keyCode, KeyEvent event) { // TODO Auto-generated method stub if (keyCode == KeyEvent.KEYCODE_MENU) { showMenu(); return true; } return super.onKeyDown(keyCode, event); } private void showMenu() { LayoutInflater inflater = getLayoutInflater(); View menuView = inflater.inflate(R.layout.pop_menu, null); Button button1 = (Button) menuView.findViewById(R.id.btn_ver_update); Button button2 = (Button) menuView.findViewById(R.id.btn_help); Button button3 = (Button) menuView.findViewById(R.id.btn_exit_qq); Button button4 = (Button) menuView.findViewById(R.id.btn_undo); button1.setOnClickListener(this); button2.setOnClickListener(this); button3.setOnClickListener(this); button4.setOnClickListener(this); // 设置PopupWindow宽高 DisplayMetrics metrics = new DisplayMetrics(); getWindowManager().getDefaultDisplay().getMetrics(metrics); double screenWidth = metrics.widthPixels * 0.95; popupWindow = new PopupWindow(menuView, (int) screenWidth, LayoutParams.WRAP_CONTENT); // 想要让PopupWindow中的控件能够使用,就必须设置PopupWindow为focusable popupWindow.setFocusable(true); // 想做到在你点击PopupWindow以外的区域时候让PopupWindow消失就做如下两步操作 // 1:设置setOutsideTouchable为ture,这个很容易理解吧,跟AlertDialog一样的 popupWindow.setOutsideTouchable(true); popupWindow.setBackgroundDrawable(getResources().getDrawable( android.R.color.transparent)); popupWindow.setAnimationStyle(R.style.AnimationPreview); popupWindow.setOnDismissListener(onDismissListener); popupWindow.showAtLocation(getWindow().getDecorView(), android.view.Gravity.BOTTOM, 0, 0); // 设置父窗口透明度 WindowManager.LayoutParams wlp = getWindow().getAttributes(); wlp.alpha = 0.5f; getWindow().setAttributes(wlp); } private OnDismissListener onDismissListener = new OnDismissListener() { @Override public void onDismiss() { WindowManager.LayoutParams wlp = getWindow().getAttributes(); wlp.alpha = 1.0f; getWindow().setAttributes(wlp); } }; @Override public void onClick(View v) { // TODO Auto-generated method stub if (popupWindow != null && popupWindow.isShowing()) popupWindow.dismiss(); switch (v.getId()) { case R.id.btn_ver_update: Toast.makeText(context, "版本更新!", Toast.LENGTH_SHORT).show(); break; case R.id.btn_help: Toast.makeText(context, "帮助与反馈!", Toast.LENGTH_SHORT).show(); break; case R.id.btn_exit_qq: Toast.makeText(context, "退出QQ!", Toast.LENGTH_SHORT).show(); break; case R.id.btn_undo: Toast.makeText(context, "取消!", Toast.LENGTH_SHORT).show(); break; } } }
BINGO~结束了,最后看一下效果图,相似度还不错吧:
<?xml version="1.0" encoding="utf-8"?> <set xmlns:android="http://schemas.android.com/apk/res/android" > <translate android:duration="350" android:fromYDelta="100%" android:toYDelta="0.0" /> </set>
anim_bottom_out.xml:
<?xml version="1.0" encoding="utf-8"?> <set xmlns:android="http://schemas.android.com/apk/res/android" > <translate android:duration="350" android:fromYDelta="0.0" android:toYDelta="100%p" /> </set>
my_btn_selector.xml:
<?xml version="1.0" encoding="utf-8"?> <selector xmlns:android="http://schemas.android.com/apk/res/android"> <item android:state_pressed="false"><shape android:shape="rectangle"> <gradient android:endColor="#efffffff" android:startColor="#efffffff"></gradient> <!-- 设置内填充 --> <padding android:bottom="7dp" android:left="7dp" android:right="7dp" android:top="7dp" /> <!-- 设置圆角矩形 --> <corners android:radius="8dp" /> </shape></item> <item android:state_pressed="true"><shape android:shape="rectangle"> <gradient android:endColor="#ecdcdcdc" android:startColor="#ecdcdcdc"></gradient> <!-- 设置内填充 --> <padding android:bottom="7dp" android:left="7dp" android:right="7dp" android:top="7dp" /> <!-- 设置圆角矩形 --> <corners android:radius="8dp" /> </shape></item> </selector>
Over,如果新手朋友仔细看了本篇blog的话相信一定会有不少的收获的~ 我个人有以下收获:
郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。