Android系統給我提供的菜單不盡人意,大多數情況下我們都是根據需求,重寫系統的菜單,達到想要的效果,下面就用PopupWindow兩種方式重寫系統菜單效果。
Android PopupWindow模擬Windows開始菜單顯示消失效果DEMO下載:
免費下載地址在 http://linux.linuxidc.com/
用戶名與密碼都是www.linuxidc.com
具體下載目錄在 /pub/Android源碼集錦/2011年/11月/Android PopupWindow模擬Windows開始菜單顯示消失效果/
- 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);
- }
-
- @Override
- public 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()
- {
- @Override
- public 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()
- {
- @Override
- public void onItemClick(AdapterView<?> parent, View view,
- int position, long id)
- {
- hideLeftMenu();
- }
- });
- // 當菜單出現時焦點會落在ListView上
- list.setOnKeyListener(new OnKeyListener()
- {
- @Override
- public 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;
- }
-
- @Override
- public 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就不會退出。
以上是第一種方法。