在app中有一些展示二级内容和活动的机制:
- 上下文动作模块 :一个动作模块会在用户选择某项后开始,在这个选项上actionbar转换成语境的模块展现出相关的动作
- 弹出菜单 模块菜单是绑定在某个视图上的,菜单展示在view的下方,被用来提供溢出的菜单允许二级动作。
- 弹出窗口 简单的对话窗口出现时会获得焦点,用来展示额外的信息
- 对话碎片 一个完全自定义的对话窗口出现在活动上方,包含在碎片中定义的全部内容。最灵活的方法但是也十分复杂
语境动作模块
关联项的重要的动作应该通过构建预警动作模块来呈现,动作模块一般出现在一个view上的长按操作或对于一个checkbox的选择。
定义
首先定义菜单的xml文件res/menu/actions_textview.xml
<menu xmlns...>
<item android:id="@+id/menu_edit"
android:title = "Edit"
android:icon = "@android:drawable/ic_menu_edit"/>
<item android:id="@+id/menu_delete"
android:title = "Delete"
android:icon="@android:drawable/ic_menu_delete"/>
</menu>
上面是语境模块中actionbar的布局然后我们定义回调函数来管理语境菜单的行为:
//定义当ActionMode激活后的回调函数
private android.view.ActionMode.Callback modelCallBack = new android.view.ActionMode.Callback() {
//当actionmode被创造时调用,startActionMode()
@Override
public boolean onCreateActionMode(android.view.ActionMode mode, Menu menu) {
mode.setTitle("Actions");
mode.getMenuInflater().inflate(R.menu.actions_viewtext, menu);
return true;
}
//每次actionmode出现时候调用
@Override
public boolean onPrepareActionMode(android.view.ActionMode mode, Menu menu) {
return false;//啥也不做returnfalse
}
@Override
public boolean onActionItemClicked(android.view.ActionMode mode, MenuItem item) {
switch (item.getItemId()) {
case R.id.menu_edit:
Toast.makeText(MainActivity.this, "Editing!", Toast.LENGTH_SHORT).show();
mode.finish();
return true;
case R.id.menu_delete:
//触发删除作用
mode.finish();
return true;
default:
return false;
}
}
//当用户退出动作模块时
@Override
public void onDestroyActionMode(android.view.ActionMode mode) {
currentActionMode = null;
}
};
最后绑定在某个view上:
public class MainActivity extends AppCompatActivity {
//跟踪上下文语境
private ActionMode currentActionMode;
//带有上下文菜单的TextView
private TextView tvName;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
tvName = (TextView) findViewById(R.id.tvName);
tvName.setOnLongClickListener(new View.OnLongClickListener() {
@Override
public boolean onLongClick(View v) {
if (currentActionMode != null) {return false;}
startActionMode(modelCallBack);
v.setSelected(true);
return true;
}
});
}
应用在AdapterView上
首先我们定义item项上应用相关模块:
public class MainActivity extends Activity {
// ListView and adapter
private ListView lvItems;
private ArrayList<String> arrayItems;
private ArrayAdapter<String> adapterItems;
// Tracks current menu item
private int currentListItemIndex;
// Tracks current contextual action mode
private ActionMode currentActionMode;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
populateListView(); // Fill array with string items and attach to listview
lvItems = (ListView) findViewById(R.id.lvItems);
lvItems.setAdapter(adapterItems);
// Setup contextual action mode when item is clicked
lvItems.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() {
public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) {
if (currentActionMode != null) { return; }
currentListItemIndex = position;
currentActionMode = startActionMode(modeCallBack);
view.setSelected(true);
return true;
}
});
}
// ... action mode definitions ....
}
现在某项长点击后会出触发语境模块,因为我们存储了currentListItemIndex
,然后我们就可以对被选中的项进行正确的操作。
private ActionMode.Callback modeCallBack = new ActionMode.Callback() {
// ...
// Called when the user selects a contextual menu item
@Override
public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
switch (item.getItemId()) {
case R.id.menu_delete:
arrayItems.remove(currentListItemIndex); // 删除当前项
adapterItems.notifyDataSetChanged(); // Refresh adapter
mode.finish(); // Action picked, so close the contextual menu
return true;
default:
return false;
}
}
// ...
};
在某些时候我们需要可能会用一个动作影响到不止一项,所以我们需要使用MultiChoiceModelListener
https://developer.android.com/guide/topics/ui/menus.html#CABforListView
PopMenu
是锚定到view的菜单,为了与特定内容相关的操作提供溢出的样式菜单。记住上下文模块一般会用于影响内容的操作,而此菜单用于与内容县官的操作,例如回复信息。
首先比如说我们想要用按钮弹出一个菜单我们为一个按钮定义一个menu的xml文件menu/popup_filters.xml
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item android:id="@+id/menu_keyword"
android:title="Keyword" />
<item android:id="@+id/menu_popularity"
android:title="Popularity" />
</menu>
然后我们在活动中为按钮绑定监听器:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//绑定相关的监听器
btnFilter = (Button) findViewById(R.id.btnFilter);
btnFilter.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
showFilterPopup(v);
}
});
//在选中的view上展示菜单
private void showFilterPopup(View v) {
PopupMenu popup = new PopupMenu(this, v);
//从xml加载菜单
popup.getMenuInflater().inflate(R.menu.popup_filters, popup.getMenu());
//建立菜单选项
popup.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
@Override
public boolean onMenuItemClick(MenuItem item) {
switch (item.getItemId()) {
case R.id.menu_keyword:
Toast.makeText(MainActivity.this, "Keyword", Toast.LENGTH_SHORT).show();
return true;
case R.id.menu_popularity:
Toast.makeText(MainActivity.this, "popularity", Toast.LENGTH_SHORT).show();
return true;
default:
return false;
}
}
});
//处理消失:popup.setOnDismissListener(...)
//展示菜单
popup.show();
}
弹出窗口
除了上述之外我们还有一个更加易定制的PopWindow,他是一个悬浮的内容容器出现在现有活动智商。适用于展示额外的信息或者事件发生后用户想要获取的信息。
首先我们要有一张背景图片,作为弹出内容的背景,然后我们定义一个弹出窗口的布局文件layout/popup_content.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/popup_bg">
<TextView
android:id="@+id/tvCaption"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true"
android:text="This is a popup!"
android:textAppearance="?android:attr/textAppearanceLarge"
android:textColor="#ffffff" />
</RelativeLayout>
然后我们需要定义displayPopupWindow
方法来构建和展示我们的窗口,基于我们的内容区域和背景图片。
public class DemoWindowActivity extends Activity {
private Button btnShowPopup;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_demo_window);
// Locate the show popup button and attach click listener
btnShowPopup = (Button) findViewById(R.id.btnShowPopup);
btnShowPopup.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// Display popup attached to the button as a position anchor
displayPopupWindow(v);
}
});
}
// Display popup attached to the button as a position anchor
private void displayPopupWindow(View anchorView) {
PopupWindow popup = new PopupWindow(DemoWindowActivity.this);
View layout = getLayoutInflater().inflate(R.layout.popup_content, null);
popup.setContentView(layout);
// Set content width and height
popup.setHeight(WindowManager.LayoutParams.WRAP_CONTENT);
popup.setWidth(WindowManager.LayoutParams.WRAP_CONTENT);
// Closes the popup window when touch outside of it - when looses focus
popup.setOutsideTouchable(true);
popup.setFocusable(true);
// Show anchored to button
popup.setBackgroundDrawable(new BitmapDrawable());
popup.showAsDropDown(anchorView);
}
}
菜单组Menu Group
在某些情况下我们可能想把菜单选项组合在一起,在XML文件中我们可以简单的使用group
标签
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item android:id="@+id/menu_save"
android:icon="@drawable/menu_save"
android:title="@string/menu_save" />
<!-- menu group -->
<group android:id="@+id/group_delete">
<item android:id="@+id/menu_archive"
android:title="@string/menu_archive" />
<item android:id="@+id/menu_delete"
android:title="@string/menu_delete" />
</group>
</menu>
库
Android-SlideExpandableListView:listView每一项都有某个区域可以划出
android-swipelistview :