接下来的例子,你将为第2章开始的To-Do List应用程序添加一些简单的菜单功能,完善先前的例子。
你将添加上下文菜单和Activity菜单删除项目的能力,并且通过只在添加新的项目时才显示文本输入框来改进屏幕空间的使用。
1. 在Activity类中导入支持菜单功能所需的包。
import android.view.Menu;
import android.view.MenuItem;
import android.view.ContextMenu;
import android.widget.AdapterView;
2. 添加私有的静态常量来定义独一无二的菜单项ID。
static final private int ADD_NEW_TODO = Menu.FIRST;
static final private int REMOVE_TODO = Menu.FIRST + 1;
3. 现在,重写onCreateOptionsMenu方法来添加两个菜单项,一个用来添加,另外一个用来删除。为菜单项指定合适的文本,图标资源和快捷键。
@Override
public boolean onCreateOptionsMenu(Menu menu) {
super.onCreateOptionsMenu(menu);
// Create and add new menu items.
MenuItem itemAdd = menu.add(0, ADD_NEW_TODO, Menu.NONE, R.string.add_new);
MenuItem itemRem = menu.add(0, REMOVE_TODO, Menu.NONE, R.string.remove);
// Assign icons
itemAdd.setIcon(R.drawable.add_new_item);
itemRem.setIcon(R.drawable.remove_item);
// Allocate shortcuts to each of them.
itemAdd.setShortcut(‘0’, ‘a’);
itemRem.setShortcut(‘1’, ‘r’);
return true;
}
如果你运行Activity,按下Menu按钮,显示如图4-7。
图4-7
4. 完成Activity菜单的填入工作后,创建上下文菜单。首先,修改onCreate方法注册ListView来接收一个上下文菜单。然后重写onCreateContextMenu来填入一个“remove”项。
@Override
public void onCreate(Bundle icicle) {
[ ... existing onCreate method ... ]
registerForContextMenu(myListView);
}
@Override
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
super.onCreateContextMenu(menu, v, menuInfo);
menu.setHeaderTitle(“Selected To Do Item”);
menu.add(0, REMOVE_TODO, Menu.NONE, R.string.remove);
}
5. 现在,通过重写onPrepareOptionsMenu方法,基于应用程序上下文来修改菜单的外观。如果你当前正在添加一个项目时,菜单应显示“cancel”而不是“delete”。
private boolean addingNew = false;
@Override
public boolean onPrepareOptionsMenu(Menu menu) {
super.onPrepareOptionsMenu(menu);
int idx = myListView.getSelectedItemPosition();
String removeTitle = getString(addingNew ? R.string.cancel : R.string.remove);
MenuItem removeItem = menu.findItem(REMOVE_TODO);
removeItem.setTitle(removeTitle);
removeItem.setVisible(addingNew || idx > -1);
return true;
}
6. 为了让第5步中的代码工作,你需要增加todoListItems和ListView的作用域超出onCreate方法。为ArrayAdapter和EditText做相同的事情,为将要实现的添加删除操作提供支持。
private ArrayList<String> todoItems;
private ListView myListView;
private EditText myEditText;
private ArrayAdapter<String> aa;
@Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
// Inflate your view
setContentView(R.layout.main);
// Get references to UI widgets
myListView = (ListView)findViewById(R.id.myListView);
myEditText = (EditText)findViewById(R.id.myEditText);
todoItems = new ArrayList<String>();
int resID = R.layout.todolist_item;
aa = new ArrayAdapter<String>(this, resID, todoItems);
myListView.setAdapter(aa);
myEditText.setOnKeyListener(new OnKeyListener() {
public boolean onKey(View v, int keyCode, KeyEvent event) {
if (event.getAction() == KeyEvent.ACTION_DOWN)
if (keyCode == KeyEvent.KEYCODE_DPAD_CENTER)
{
todoItems.add(0, myEditText.getText().toString());
myEditText.setText(“”);
aa.notifyDataSetChanged();
return true;
}
return false;
}
});
registerForContextMenu(myListView);
}
7. 接下来你需要处理菜单项的点击事件。重写onOptionsItemSelected和onContextItemSelected方法来处理新的菜单项点击。
7.1. 重写onOptionsItemSelected来处理Activity菜单的选择。对于删除菜单项,你可以使用ListView的getSelectedItemPosition方法来查找当前高亮的项。
@Override
public boolean onOptionsItemSelected(MenuItem item) {
super.onOptionsItemSelected(item);
int index = myListView.getSelectedItemPosition();
switch (item.getItemId())
{
case (REMOVE_TODO):
{
if (addingNew)
{
cancelAdd();
}
else
{
removeItem(index);
}
return true;
}
case (ADD_NEW_TODO):
{
addNewItem();
return true;
}
}
return false;
}
7.2. 接下来重写onContextItemSelected来处理上下文菜单选择。注意,你正在使用AdapterView特定的ContextMenuInfo实现。这里,包含触发上下文菜单的View的引用和位置信息。
使用下面的方法找到要删除的项的索引。
@Override
public boolean onContextItemSelected(MenuItem item) {
super.onContextItemSelected(item);
switch (item.getItemId())
{
case (REMOVE_TODO):
{
AdapterView.AdapterContextMenuInfo menuInfo;
menuInfo =(AdapterView.AdapterContextMenuInfo)item.getMenuInfo();
int index = menuInfo.position;
removeItem(index);
return true;
}
}
return false;
}
7.3. 创建在菜单项选择处理函数中调用的方法的原型。
private void cancelAdd() {
}
private void addNewItem() {
}
private void removeItem(int _index) {
}
8. 现在实现每一个函数,来提供新的功能。
private void cancelAdd() {
addingNew = false;
myEditText.setVisibility(View.GONE);
}
private void addNewItem() {
addingNew = true;
myEditText.setVisibility(View.VISIBLE);
myEditText.requestFocus();
}
private void removeItem(int _index) {
todoItems.remove(_index);
aa.notifyDataSetChanged();
}
9. 接下来,在你完成添加一个新的项目时需要隐藏输入框。在onCreate方法里,修改onKeyListener方法,在添加完成后调用cancelAdd函数。
myEditText.setOnKeyListener(new OnKeyListener() {
public boolean onKey(View v, int keyCode, KeyEvent event)
{
if (event.getAction() == KeyEvent.ACTION_DOWN)
if (keyCode == KeyEvent.KEYCODE_DPAD_CENTER)
{
todoItems.add(0, myEditText.getText().toString());
myEditText.setText(“”);
aa.notifyDataSetChanged();
cancelAdd();
return true;
}
return false;
}
});
10. 最后,为了保证UI的一致性,修改main.xml layout,隐藏文本输入框直到用户选择添加一个新的项目。
<EditText
android:id=”@+id/myEditText”
android:layout_width=”fill_parent”
android:layout_height=”wrap_content”
android:text=””
android:visibility=”gone”
/>
运行应用程序,你需要触发Activity的菜单来添加或删除列表,并且每个项目应该提供上下文菜单来删除它。