android系统给我提供的菜单不尽人意,大多数情况下我们都是根据需求,重写系统的菜单,达到想要的效果,下面就用PopupWindow两种方式重写系统菜单效果。

package com.jacp.app;import android.app.Activity;import android.content.Intent;import android.os.Bundle;import android.view.Gravity;import android.view.KeyEvent;import android.view.MotionEvent;import android.view.View;import android.view.View.OnClickListener;import android.view.View.OnKeyListener;import android.view.View.OnTouchListener;import android.view.WindowManager;import android.widget.AdapterView;import android.widget.AdapterView.OnItemClickListener;import android.widget.LinearLayout;import android.widget.ListView;import android.widget.PopupWindow;public class PopupWindowActivity extends Activity implements OnClickListener {private PopupWindow mLeftMenu;    @Override    public void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.main);        // 注册按钮事件        findViewById(R.id.left).setOnClickListener(this);        findViewById(R.id.right).setOnClickListener(this);    }@Overridepublic void onClick(View v) {switch (v.getId()) {case R.id.left:showLeftMenu();break;case R.id.right:startActivity(new Intent(this, PopupWindowSecondActivity.class));break;}}/** * 显示菜单 * @return 如果菜单显示则返回true,否则返回false */private boolean showLeftMenu() {if (hideLeftMenu()){return false;}LinearLayout leftLayout = (LinearLayout) getLayoutInflater().inflate(R.layout.menu_list, null);// 当菜单出现时,最外层布局接受Touch事件leftLayout.setOnTouchListener(new OnTouchListener(){@Overridepublic boolean onTouch(View v, MotionEvent event){hideLeftMenu();return false;}});ListView list = (ListView) leftLayout.findViewById(R.id.item_list);String[] data = getResources().getStringArray(R.array.menu_item);int[] res = new int[data.length];for (int i = 0, length = data.length; i < length; i++){res[i] = R.drawable.icon;}list.setAdapter(new PopupAdapter(this, data, res, R.layout.menu_item, R.id.item_image, R.id.item_text));list.setOnItemClickListener(new OnItemClickListener(){@Overridepublic void onItemClick(AdapterView<?> parent, View view,int position, long id){hideLeftMenu();}});// 当菜单出现时焦点会落在ListView上list.setOnKeyListener(new OnKeyListener(){@Overridepublic boolean onKey(View v, int keyCode, KeyEvent event){// 此方法会调两次,一次Down和一次Up// 所以此处要拦截if (event.getAction() == KeyEvent.ACTION_DOWN){switch (keyCode){case KeyEvent.KEYCODE_MENU:return hideLeftMenu();case KeyEvent.KEYCODE_BACK:return hideLeftMenu();}}return false;}});// 设置菜单属性mLeftMenu = new PopupWindow(leftLayout, WindowManager.LayoutParams.WRAP_CONTENT, WindowManager.LayoutParams.WRAP_CONTENT);mLeftMenu.setWidth(150);// 设置菜单上是否可以聚焦mLeftMenu.setFocusable(true);// 当菜单出现时菜单以外的区域是否接受点击事件mLeftMenu.setOutsideTouchable(true);// 设置菜单显示的位置mLeftMenu.showAtLocation(leftLayout, Gravity.BOTTOM | Gravity.LEFT, 0, 80);return true;}/** * 隐藏菜单 * @return 如果菜单隐藏则返回true,则否返回false */private boolean hideLeftMenu(){if (null != mLeftMenu && mLeftMenu.isShowing()){mLeftMenu.dismiss();mLeftMenu = null;return true;}return false;}@Overridepublic boolean onKeyDown(int keyCode, KeyEvent event){switch (keyCode) {case KeyEvent.KEYCODE_BACK:hideLeftMenu();break;case KeyEvent.KEYCODE_MENU:showLeftMenu();break;}return super.onKeyDown(keyCode, event);}}
其中有三点要注意:

1.PopupWindow的参数设置

// 设置菜单上是否可以聚焦mLeftMenu.setFocusable(true);// 当菜单出现时菜单以外的区域是否接受点击事件mLeftMenu.setOutsideTouchable(true);
2.当PopupWindow显示时焦点会落在其中,所以监听事件的是它里面的View,如例中的Touch事件。按键事件是占整个View的ListView监听的。很奇怪的是不是里面的LinearLayout,如果高人知道,请在下面留言,小弟不甚感激。

3.最后一点是注意按键事件。例子中重写了Activity的OnKeyDown事件,而在ListView中的OnKey方法必须拦截KeyDown事件。如果不拦截菜单出现就会消失,因为OnKey方法会因Down和Up调用两次;如果拦截的是Up事件,情况也是一样的,因为当菜单没有出现按Menu键时,先执行Activity里面的onKeyDown事件,菜单出现。注意菜单出现是Down事件,那Up呢?正好当PopupWindow出现时,ListView继续执行事件,会执行OnKey事件,如果是拦截的Action是Up则会执行,所以整个事件会两个地方执行。有人说在Activity里面的OnKeyDown事件return true进行拦截不就行了,这样事件就不会执行到PopupWindow上面,这样想没有错,如果真的是那样,那按Back键后,整个Activity就不会退出。


以上是第一种方法,下面请看第二种方法:

package com.jacp.app;import android.app.Activity;import android.os.Bundle;import android.view.Gravity;import android.view.KeyEvent;import android.view.MotionEvent;import android.view.View;import android.view.View.OnClickListener;import android.view.View.OnKeyListener;import android.view.View.OnTouchListener;import android.view.WindowManager;import android.widget.LinearLayout;import android.widget.ListView;import android.widget.PopupWindow;public class PopupWindowSecondActivity extends Activity implements OnClickListener {private PopupWindow mRightMenu;@Overrideprotected void onCreate(Bundle savedInstanceState){super.onCreate(savedInstanceState);setContentView(R.layout.main);findViewById(R.id.left).setVisibility(View.GONE);        findViewById(R.id.right).setOnClickListener(this);}@Overridepublic void onClick(View v){switch (v.getId()){case R.id.right:showRightMenu();break;}}/** * 显示菜单 * @return 如果菜单显示返回true,否则返回false */private boolean showRightMenu(){if (hideRightMenu()){return false;}// 加载布局内容LinearLayout centerLayout = (LinearLayout) getLayoutInflater().inflate(R.layout.menu_list, null);centerLayout.setOnTouchListener(new OnTouchListener(){@Overridepublic boolean onTouch(View v, MotionEvent event){hideRightMenu();return false;}});ListView list = (ListView) centerLayout.findViewById(R.id.item_list);String[] data = getResources().getStringArray(R.array.menu_item);int[] res = new int[data.length];for (int i = 0, length = data.length; i < length; i++){res[i] = R.drawable.icon;}list.setAdapter(new PopupAdapter(this, data, res, R.layout.menu_item, R.id.item_image, R.id.item_text));list.setOnKeyListener(new OnKeyListener(){@Overridepublic boolean onKey(View v, int keyCode, KeyEvent event){if (event.getAction() == KeyEvent.ACTION_DOWN){switch (keyCode){case KeyEvent.KEYCODE_MENU:showRightMenu();break;}}return false;}});// 设置菜单属性mRightMenu = new PopupWindow(this);mRightMenu.setContentView(centerLayout);mRightMenu.setWidth(150);mRightMenu.setHeight(WindowManager.LayoutParams.WRAP_CONTENT);// 设置菜单上是否可以聚焦mRightMenu.setFocusable(true);// 当菜单出现时菜单以外的区域是否接受点击事件mRightMenu.setOutsideTouchable(true);mRightMenu.showAtLocation(centerLayout, Gravity.RIGHT | Gravity.BOTTOM, 0, 80);return true;}/** * 隐藏菜单 * @return 如果菜单隐藏则返回true,否则返回false */private boolean hideRightMenu(){if (null != mRightMenu && mRightMenu.isShowing()){mRightMenu.dismiss();mRightMenu = null;return true;}return false;}@Overridepublic boolean onKeyDown(int keyCode, KeyEvent event){switch (keyCode){case KeyEvent.KEYCODE_BACK:hideRightMenu();break;case KeyEvent.KEYCODE_MENU:showRightMenu();break;}return super.onKeyDown(keyCode, event);}}

这两个的不同点有二:

1.创建PopupWindow时传的参数不同;

2.第二种方式中的ListView的onKey事件中少了一个KEYCODE_MENU,而达到了和第一种同样的效果。

感觉这样的区别很奇怪,为此还看了一下源代码,但没有找到答案。唯一的就是想知道当前的Activity和View.getContext()有啥区别,因为在源码中如果没有传Context过去,Context就是通过View.getContext()获得到的。望大神指点!

示例下载地址:http://download.csdn.net/source/3555098

更多相关文章

  1. View的事件体系《Android开发艺术探索》笔记
  2. [Flutter]监听Android返回键事件
  3. Cordova 3.x 源码分析(7) -- CordovaLib概要
  4. 关于JAVA回调函数和Android事件响应
  5. onInterceptTouchEvent和onTouchEvent调用时序2
  6. 在android里用ExpandableListView实现二层和三层列表源码
  7. android事件处理的四种写法--电话拨号为例
  8. 仿QQ下拉菜单列表 自定义Spinner
  9. 【Android】常量DEFAULT_KEYS_SHORTCUT 功能的验证 及其 源码实

随机推荐

  1. Android Question - “Id cannot be reso
  2. android 获取系统和SD卡音乐
  3. android.os.NetworkOnMainThreadExceptio
  4. android webview 中处理网页中的400、404
  5. Android Fresco的使用
  6. Android图片解决方案
  7. Android的字符编码转换问题,Unicode,GB2312
  8. android 项目收获01
  9. android中dialog工具类的实现(多种dialog
  10. android根据包名获取签名MD5信息