• 热门专题

处女男学Android(十二) Android菜单(Menu)详解与应用

作者:  发布日期:2015-01-03 23:38:50
Tag标签:处女  菜单  
  • 一、前言

    出处: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/> 下面分别说明一下这两个标签的用法和属性,首先是最常用的<item/>,<item/>元素用于定义一个菜单项,<item/>元素中又可以包含新的<menu/>,而位于<item/>中的<menu/>自然就代表了指定<item/>的子菜单了。下面先看一下<item/>可指定的常用属性:

    通常我们必须指定的属性只有一个,就是android:title,其余的属性都是可选的,这里我们创建的第一个菜单简单一些,只给出id和title即可:
    <?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;
    	}
    最后看一下运行效果:


    三、选项菜单(Options menu)和上下文菜单(Context menu)

    google将菜单按功能特性分为了三种,分别是:选项菜单(Options menu)、上下文菜单(Context menu)以及弹出式菜单(Popup menu),现在就分别介绍一下前两个:选项菜单和上下文菜单。
    a.选项菜单(Option menu)
    首先看一下官方文档中对option menu的简介: ————————————————————————————
    ———————————————————————————— 简单翻译一下,“选项菜单”是一个Activity中主要的菜单项的集合,在它上面应该放置有全局性影响的功能,例如:“搜索”、“写邮件”和“设置”。说到这里我们差不多应该就能对号入座了选项菜单了,安卓系统就自带了“选项菜单”,也就是下图的这个菜单:
    点击手机的Menu键,弹出的就是我们所说的options menu了,再看一下菜单上提供的功能,分别是:墙纸(Wallpaper)、APP管理器(Manage apps)和系统设置(System settings),这也和文档中提到的“放置全局性影响的功能”相吻合。但是由于从Android3.0版本开始,并不要求手机上必须提供Menu键,而且有可能部分手机将不再提供Menu键(比如我的魅族MX4),在这种情况下,google推荐我们使用ActionBar去替代options menu这种需求。 示例代码已经写过了,刚才“创建的第一个菜单”就是一个简单标准的options menu了。
    b.上下文菜单(Context menu)

    首先看一下官方文档对Context menu的概述:
    重点是第一句话,简单翻译一下,context menu是一个浮动的菜单,当用户在某个view上执行长按操作时弹出。好了概念上就这么简单,那么一般什么情况下会用到它呢?其实这个具体看需求,不过官方也做了相关说明:
    没错,经常用在ListView、GridView的Items上面,可想而知也确实如此,经常会有这种需求,长按ListView弹出一个dialog或者一个menu,比如百度搜索中应该就是一个标准的context menu了,如下图:
    可以看到,当我长按一条Item的时候,会弹出这样的一个菜单,它就是context menu,下面就具体介绍一下context menu的创建方式。
    与options menu类似,但是在Activity中还是有些许的差别,依旧来看一下官方文档:
    可以看到,第一步就是为我们的上下文菜单注册一个View,也就是说当我们长按哪个View的时候才需要弹出菜单,当我们希望ListView或GridView的items提供相同的菜单的话,那么直接传一个ListView或GridView即可完成。下面的代码就是模仿上面百度的那个菜单的,接下来一一贴出代码,首先是在Activity中为上下文菜单注册一个View:
    	@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
    	}
    下面看一下接下来的需要做的事情,文档中也已经说的很清楚了:

    可以看到,这里重写的是onCreatContextMenu方法,而选项菜单重写的是onOptionsMenu,这也就是它们最主要的区别了。可以看到这个方法并不需要返回值,所以直接通过MenuInflater加载一下菜单的资源文件就OK了。
    如果希望应用程序能够为菜单提供响应,同样的需要再重写一个相应方法,与options menu的类似但也有些许不同: 很简单,不做单独说明了,下面就看一下仿百度的上下文菜单的完整示例代码。
    首先是activity的布局文件:
    <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的适用场合,最后看一下运行效果图:


    四、弹出菜单(Popup menu)

    看到pop这个词很明显的可以知道它肯定是类似于popupwindow,是一个弹出式的菜单,而且肯定也和popupwindow有很多相似的特性,依旧看一下官方文档对于popupmenu的概述:
    简单翻译一下,popup menu是一个停靠在固定View上的模式菜单,如果该View下方有空间,那么弹出菜单将显示在该View的下方,否则会显示在该View的上方。不难理解popup menu是依附于一个View的,也就是说在指定View的上方or下方弹出,这种菜单一般会从顶部弹出或者从底部弹出,在很多APP中都很常见这种菜单,比如微信主界面右上角的加号图标,点击就会弹出一个popupmenu。
    接下来介绍一下popup menu的创建方式,同popup window很类似,仅需三步: 1.通过其构造方法new PopupMenu(Context context,View anchor)创建下拉菜单,第二个参数即表示本菜单所依附的View。 2.调用MenuInflater的inflate()方法装载menu的资源文件。 3.调用popup menu的show()方法来显示菜单即可。 很简单吧,也没啥好说的,下面就模仿微信的那个弹出菜单做一个小例子,直接贴代码。
    Activity布局文件:
    <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;
    				}
    			});
    		}
    	}
    
    }

    是不是超简单的说,下面看一下运行效果:


    五、模仿手机QQ的底部弹出菜单

    介绍完了所有类型的菜单之后,最后再做一个练习,可能我们也发现了菜单的样式比较局限,一般很难做一些定制的样式,所以说还有一种很不错的解决方案就是不使用Menu的API,通过监听菜单键的KEY CODE来弹出一个popup window,这样的话我们做一些个性化的样式、动画等等就没有那么多限制了,在这里我就通过这种方式来模仿一下手机QQ的功能菜单,下面是效果图:
    可以看到,当我们进入QQ之后点击手机的Menu键时,会从底部弹出图中圈出的菜单,下面就结合popup window来实现这个效果,首先将需要做的事情拆分为三个步骤: step 1 在Activity中重写onKeyDown()方法,并通过KEY CODE来监听菜单键按下的事件,并在该事件中弹出一个popup window。 step 2 构造popup window对象,并编写布局文件代码,设置样式以及动画。 step 3 点击菜单键时show这个popup window,点击菜单键或者popup window之外的区域时dismiss这个popup window。
    好了,接下来就按步骤去实现它,首先是第一步,重写onKeyDown()方法用来响应菜单键的单击,直接贴代码:
    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;
    	}
    
    }
    

    很简单,看一下效果图:


    第二步和第三步一起说了,编写popup window的布局文件代码,我能想到的最简单的办法就是通过一组Button来实现,然后需要为popupwindow添加一个弹出动画,直接看代码,下面分别是popupwindow的布局文件和Activity中的全部代码。
    popup_menu.xml:
    <?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~结束了,最后看一下效果图,相似度还不错吧:

    关于样式的话,每个按钮都是通过selector+shape嵌套实现的,popup window弹出的时候还设置了一个非常简单的补间动画,背景色直接用透明色值就OK了,下面把两个动画的资源文件和一个按钮的样式资源文件贴出来(其余的类似)。
    anim_bottom_in.xml:
    <?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的话相信一定会有不少的收获的~ 我个人有以下收获: 1.学习了Android中的3种Menu的概念和简单的使用方法(Options menu、Context menu、Popup menu)。 2.学习了Android简单动画的编写和引用。 3.学习了selector和shape的嵌套。 4.学习并复习了以下的几个小知识点:改变popupwindow父窗体透明度、shape资源中关于4个corners的任意控制、根据DisplayMetrix来设置popupwindow的宽度、根据KEY CODE监听菜单键的动作、关于ScrollView嵌套ListView滚动冲突的问题等等。

    六、总结

    也许这一篇blog的标题不够吸引人,内容也没有别的大神写的那么深刻高端,但我认为这算是我写过的最认真的博客之一了,用了很长时间。从翻译文档、修改图片到录制gif,对每一个知识点和概念咬文嚼字,斟酌再三,不放过每一个细节,总的来说我的收获还是蛮大的,至少在我的下一个APP中我一定会用到上面写的那个仿QQ的“菜单”。在今后的blog中我还会尽我最大的努力去做到“认真”、“细心”和“完美”,因为我是处女座。好了,废话不多说,继续滚去加班写服务端了,但同时Android的学习我也绝不会拉下的,以csdn为证!加油,Raito!

About IT165 - 广告服务 - 隐私声明 - 版权申明 - 免责条款 - 网站地图 - 网友投稿 - 联系方式
本站内容来自于互联网,仅供用于网络技术学习,学习中请遵循相关法律法规