該目錄為Android開發秘籍學習筆記關于截取實體按鍵事件和建構菜單
截取實體按鍵事件:
标準Android裝置擁有多個可以觸發事件的實體按鍵,如下:
Android常用的實體按鍵及其觸發事件 KEYCODE_POWER 電源鍵 KEYCODE_MENU 菜單鍵 KEYCODE_BACK 後退鍵
* KEYCODE_HOME Home鍵 KEYCODE_CAMERA 相機鍵 KEYCODE_SEARCH 查找鍵 KEYCODE_VOLUME_UP
* 音量鍵+ KEYCODE_VOLUME_DOWN 音量鍵- KEYCODE_VOLUME_MUTE 靜音 方向鍵 KEYCODE_DPAD_CENTER
* KEYCODE_DPAD_UP KEYCODE_DPAD_DOWN KEYCODE_DPAD_LEFT KEYCODE_DPAD_RIGHT 鍵盤鍵
* 數字0~9 字母A~Z KEYCODE_0 ~ KEYCODE_9 KEYCODE_A ~ KEYCODE_Z 提供的回調方法有
<span style="font-family:Microsoft YaHei;font-size:14px;"> * onKeyUp()、OnKeyDown()、onKeyLongPress()</span>
系統首先會将KeyEvent發送給目前獲得焦點的Activity或視圖中适宜的回調方法,下面給出這些回調方法。
- onKeyUp()、onKeyDown()、onKeyLongPress():實體按鍵按下的回調方法。
- onTrackballEvent()、onTouchEvent():軌迹球及觸屏操作的回調方法。
- onFoucsChanged():視圖獲得或失去焦點時的回調方法。
這裡給出例子:
/**
* 重寫onKeyDown方法可以攔截系統預設的處理
*/
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
// TODOAuto-generated method stub
if (keyCode == KeyEvent.KEYCODE_BACK) {
Toast.makeText(this, "後退鍵", Toast.LENGTH_SHORT).show();
return true;
} else if (keyCode == KeyEvent.KEYCODE_VOLUME_UP) {
Toast.makeText(this, "聲音+", Toast.LENGTH_SHORT).show();
return false;
} else if (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN) {
Toast.makeText(this, "聲音-", Toast.LENGTH_SHORT).show();
return false;
} else if (keyCode == KeyEvent.KEYCODE_VOLUME_MUTE) {
Toast.makeText(this, "靜音", Toast.LENGTH_SHORT).show();
return false;
} else if (keyCode == KeyEvent.KEYCODE_HOME) {
Toast.makeText(this, "Home", Toast.LENGTH_SHORT).show();
return true;
}// 電源鍵和Home鍵是系統截獲的,不會觸及應用程式的自定義
return super.onKeyDown(keyCode, event);
}
/**
* 重寫onTouchEvent方法可以處理Touch事件
*/
@Override
public boolean onTouchEvent(MotionEvent event) {
// TODO Auto-generated method stub
if (event.getAction() == MotionEvent.ACTION_MOVE) {
Toast.makeText(this, "ACTION_MOVE", Toast.LENGTH_SHORT).show();
} else if (event.getAction() == MotionEvent.ACTION_UP) {
Toast.makeText(this, "ACTION_UP", Toast.LENGTH_SHORT).show();
} else if (event.getAction() == MotionEvent.ACTION_DOWN) {
Toast.makeText(this, "ACTION_DOWN", Toast.LENGTH_SHORT).show();
}
return super.onTouchEvent(event);
}
在代碼中,大家可以發現onKeyDown()中有的實體按鍵事件return true;有的return false;倘若return true則是把事件“消耗”(consume)掉,即讓它本來的功能失去掉。比如上面的KeyEvent.KEYCODE_BACK本來是要執行finish()操作的,但是你按手機上的BACK鍵,它并不會執行finish()。因為它被“消耗”掉了。因為事件被消耗掉了以後,就不會傳遞給其他Android元件了,但有幾個例外。
- 電源鍵和HOME鍵是由系統截獲的,不會觸及應用程式的自定義。
- 對後退鍵、菜單鍵、HOME鍵和搜尋鍵不應攔截KeyDown事件,而應該攔截KeyUp。這點與Android2.0的建議一緻,因為在某些平台上這些按鈕不見得是真實的實體按鍵。是以上例中點選HOME鍵,即使是return true,它仍然會退回到主螢幕。
建構菜單:
在Android中,開發者可以實作三種類型的菜單----選項菜單,上下文菜單,子菜單。
- 選項菜單:Activity的主菜單,當按下菜單鍵時就會顯示出來。對于Android API level 10或者更低版本,它包含一個圖示菜單(icon menu),還可能包含一個會在“更多”菜單項被選中時彈出的擴充菜單(extended menu)。較新的Android版本隻有原始的選項菜單。
- 上下文菜單:一個浮動的菜單項清單,當長按某個視圖時出現。
- 子菜單:一個浮動菜單項清單,當某個菜單項被選中時會出現。
菜單建構的一個例子:
import android.app.Activity;
import android.os.Bundle;
import android.view.ContextMenu;
import android.view.ContextMenu.ContextMenuInfo;
import android.view.KeyEvent;
import android.view.Menu;
import android.view.MenuItem;
import android.view.MotionEvent;
import android.view.SubMenu;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.TextView;
import android.widget.Toast;
public class MainActivity extends Activity {
private final int MENU_ADD = 1, MENU_SEND = 2, MENU_DEL = 3;
private final int GROUP_DEFAULT = 0, GROUP_DEL = 1;
private final int ID_DEFAULT = 0;
private final int ID_TEXT1 = 1, ID_TEXT2 = 2, ID_TEXT3 = 3;
private String[] choices = { "Press me", "Try again", "Change me" };
private static int itemNum = 0;
private static TextView tv;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
tv = (TextView) findViewById(R.id.tv);
registerForContextMenu(tv);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
menu.add(GROUP_DEFAULT, MENU_ADD, 0, "ADD").setIcon(
R.drawable.ic_launcher);
menu.add(GROUP_DEFAULT, MENU_SEND, 0, "Send");
menu.add(GROUP_DEFAULT, MENU_DEL, 0, "Delete");
return super.onCreateOptionsMenu(menu);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case MENU_ADD:
create_note();
return true;
case MENU_SEND:
send_note();
return true;
case MENU_DEL:
delete_note();
return true;
default:
break;
}
return super.onOptionsItemSelected(item);
}
private void delete_note() {
itemNum--;
}
private void send_note() {
Toast.makeText(this, "ItemNum:" + itemNum, Toast.LENGTH_SHORT).show();
}
private void create_note() {
itemNum++;
}
@Override
public boolean onPrepareOptionsMenu(Menu menu) {
if (itemNum > 0) {
menu.setGroupVisible(GROUP_DEL, true);
} else {
menu.setGroupVisible(GROUP_DEL, false);
}
return super.onPrepareOptionsMenu(menu);
}
@Override
public void onCreateContextMenu(ContextMenu menu, View v,
ContextMenuInfo menuInfo) {
if (v.getId() == R.id.tv) {
SubMenu textMenu = menu.addSubMenu("Change Text");
textMenu.add(0, ID_TEXT1, 0, choices[0]);
textMenu.add(0, ID_TEXT2, 0, choices[1]);
textMenu.add(0, ID_TEXT3, 0, choices[2]);
menu.add(0, ID_DEFAULT, 0, "Original TEXT");
}
super.onCreateContextMenu(menu, v, menuInfo);
}
@Override
public boolean onContextItemSelected(MenuItem item) {
return super.onContextItemSelected(item);
}
}
這個例子把所有的菜單類型全部包括進去了。下面就解析下這個例子---- onCreateOptionsMenu()方法隻被調用一次,在Activity的其他部分不需要被再次構。然而,如果在運作時需要改變任意菜單選項,可以随時調用onPrepareOptionMenu()方法。如果選項菜單中的某一項被點選,onOptionsItemSelected()方法會被調用。調用時會傳遞選中的菜單項的ID,可以使用switch語句來确定被選中的選項是哪個。接下來就是Menu.add()這個函數了
public abstract MenuItem add (int groupId, int itemId, int order, CharSequence title)
Added in API level 1
Add a new item to the menu. This item displays the given title for its label.
Parameters
groupId The group identifier that this item should be part of. This can be used to define groups of items for batch state changes. Normally use NONE if an item should not be in a group.
itemId Unique item ID. Use NONE if you do not need a unique ID.
order The order for the item. Use NONE if you do not care about the order. See getOrder().
title The text to display for the item.
Returns
The newly added menu item. <span style="color:#ff0000;">
</span>
可以看到add()方法的第一個參數為菜單項組設定名字标簽。同一組中的菜單項可以被一起處理。第二個參數是代表菜單項的整型ID号,它被傳遞給回調函數,以确定哪個菜單項被選中。第三個參數是菜單中項目的順序。如果不給定該參數,則按項目被添加到Menu對象上的次序來決定項目的順序。最後一個參數是菜單項顯示的文本,該參數可以是一個String型變量或是一個項R.String.mylabel這樣的字元串源。接下來就是上下文菜單了,可以在onCreate()中看到 registerForContextMenu(tv);這是為某個視圖注冊一個上下文菜單(Context Menu),當該視圖被長按時,會調用onCreateContextMenu來建立上下文菜單。此處通過addSubMenu()方法來為Menu執行個體實作SubMenu。子菜單項随主菜單項一同被指定,無論哪個菜單中的選項被選中,都會調用onContextItemSelected()方法。
效果圖:
