Contextual action mode
Contextual action mode是 ActionMode
的系统实现,关注于执行上下文相关动作的用户交互。
当用户通过选择一个项目使能这个模式,一个contextual action bar就会出现在屏幕上方,显示用户对当前选中的项目可以执行的动作。
当这个模式使能时,用户可以:选择多个项目(如果你允许的话)、取消项目选择、在activity中继续浏览(只要你允许)。
当用户取消对所有项目的选择、按下Back键、或者点击bar左边的完成按钮之后,action mode就被禁用,contextual action bar消失。
注意:contextual action bar没有必须和 action bar关联,它们是独立的。
CAB的使用情形
对于提供上下文动作的View,通常在这两种情况下(情况之一或both)调用contextual action mode:
1.用户在View上长按;
2.用户选择了View中的CheckBox或者类似控件。
你的应用如何invoke这个contextual action mode,以及如何定义每个action取决于你自己的设计。
两种基本的设计:
1.对个体任意views的上下文相关操作;
For contextual actions on individual, arbitrary views.
2.对一组数据的批处理,比如ListView或GridView中的项目,允许用户选择多个项目然后对它们整体执行一个动作。
For batch contextual actions on groups of items in a ListView or GridView (allowing the user to select multiple items and perform an action on them all).
下面分别讲讲这两种情景下的实现。
Enabling the contextual action mode for individual views
如果你想在用户选择指定View的时候invoke contextual action mode(CAB),你应该:
1.实现ActionMode.Callback
接口。
在这个接口的回调方法中,你可以指定contextual action bar的动作,响应action items的点击事件,还有处理action mode的生命周期事件。
2.当你想要show这个bar的时候(比如用户长按view的时候),调用 startActionMode()
方法。
例子代码:
package com.example.mengdd.hellocontextmenu;
import android.app.Activity;
import android.os.Bundle;
import android.view.ActionMode;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnLongClickListener;
import android.widget.TextView;
import android.widget.Toast;
public class ContextualActionModeActivity extends Activity {
private TextView mTextView = null;
private ActionMode mActionMode = null;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_contextual_action_mode);
mTextView = (TextView) findViewById(R.id.textView2);
mTextView.setOnLongClickListener(new OnLongClickListener() {
@Override
public boolean onLongClick(View view) {
if (mActionMode != null) {
return false;
}
// Start the CAB using the ActionMode.Callback defined above
mActionMode = startActionMode(mActionModeCallback);
view.setSelected(true);
return true;
}
});
}
private ActionMode.Callback mActionModeCallback = new ActionMode.Callback() {
// Called when the action mode is created; startActionMode() was called
@Override
public boolean onCreateActionMode(ActionMode mode, Menu menu) {
// Inflate a menu resource providing context menu items
MenuInflater inflater = mode.getMenuInflater();
inflater.inflate(R.menu.context_menu1, menu);
return true;
}
// Called each time the action mode is shown. Always called after
// onCreateActionMode, but
// may be called multiple times if the mode is invalidated.
@Override
public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
return false; // Return false if nothing is done
}
// Called when the user selects a contextual menu item
@Override
public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
switch (item.getItemId()) {
case R.id.edit:
showEditor();
mode.finish(); // Action picked, so close the CAB
return true;
default:
return false;
}
}
// Called when the user exits the action mode
@Override
public void onDestroyActionMode(ActionMode mode) {
mActionMode = null;
}
};
private void showEditor() {
Toast.makeText(ContextualActionModeActivity.this, "edit",
Toast.LENGTH_LONG).show();
}
}
Enabling batch contextual actions in a ListView or GridView
对于ListView和GridView这样的集合类,想让用户进行批处理操作,应该如下:
1.实现 AbsListView.MultiChoiceModeListener
接口,通过setMultiChoiceModeListener()方法把它set进集合类控件。
在这个listener的回调方法中,你可以指定contextual action bar的动作,响应action item的点击事件,处理其他继承自ActionMode.Callback的回调。
2.调用 setChoiceMode()
方法,使用参数 CHOICE_MODE_MULTIPLE_MODAL
。
package com.example.demos;
import android.app.ListActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.ActionMode;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.widget.ArrayAdapter;
import android.widget.AbsListView.MultiChoiceModeListener;
import android.widget.ListView;
import android.widget.Toast;
/**
* This demo illustrates the use of CHOICE_MODE_MULTIPLE_MODAL, a.k.a. selection mode on ListView.
*/
public class MainActivity extends ListActivity {
protected static final String TAG = "yxf";
private String[] mStrings = Cheeses.sCheeseStrings;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ListView lv = getListView();
lv.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE_MODAL);
lv.setMultiChoiceModeListener(mMultiListener);
setListAdapter(new ArrayAdapter<String>(this,
android.R.layout.simple_list_item_checked, mStrings));
}
@Override
protected void onPostCreate(Bundle savedInstanceState) {
super.onPostCreate(savedInstanceState);
getActionBar().setSubtitle("Long press to start selection");
}
private MultiChoiceModeListener mMultiListener = new MultiChoiceModeListener() {
@Override
public boolean onCreateActionMode(ActionMode mode, Menu menu) {
Log.d(TAG,"onCreateActionMode");
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.list_select_menu, menu);
mode.setTitle("Select Items");
setSubtitle(mode);
return true;
}
/*Here you can perform updates to the CAB due to an invalidate() request. */
@Override
public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
Log.d(TAG,"onPrepareActionMode");
return true;
}
/*
* 当用户选择一个上下文菜单项时被调用。
*/
@Override
public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
Log.d(TAG,"onActionItemClicked");
//Called when the user selects a contextual menu item.
switch (item.getItemId()) {
case R.id.share:
Toast.makeText(MainActivity.this, "Shared " + getListView().getCheckedItemCount() +
" items", Toast.LENGTH_SHORT).show();
mode.finish();
break;
default:
Toast.makeText(MainActivity.this, "Clicked " + item.getTitle(),
Toast.LENGTH_SHORT).show();
break;
}
return true;
}
//Called when the user exits the action mode
@Override
public void onDestroyActionMode(ActionMode mode) {
Log.d(TAG,"onDestoryActionMode");
}
/**
* 选中或者解除选中时调用,它监听的是listview中的某一项,处于选中状态则checked为true;处于解除状态则为 false。
*/
@Override
public void onItemCheckedStateChanged(ActionMode mode,
int position, long id, boolean checked) {
Log.d(TAG,"onItemCheckedStateChanged,checked = " + checked);
/*
* Here you can do something when items are selected/de-selected,
* such as update the title in the CAB(Context Action Bar).
*/
setSubtitle(mode);
}
private void setSubtitle(ActionMode mode) {
final int checkedCount = getListView().getCheckedItemCount();
switch (checkedCount) {
case 0:
mode.setSubtitle(null);
break;
case 1:
mode.setSubtitle("One item selected");
break;
default:
mode.setSubtitle("" + checkedCount + " items selected");
break;
}
}
};
}
class Cheeses {
public static final String[] sCheeseStrings = {
"Abbaye de Belloc", "Abbaye du Mont des Cats", "Abertam", "Abondance", "Ackawi",
"Acorn", "Adelost", "Affidelice au Chablis", "Afuega'l Pitu", "Airag", "Airedale"
};
}