OptionsMenu
在介紹Toolbar的時候,已經(jīng)介紹了OptionsMenu的用法,OptionsMenu稱為選項菜單,它可以設(shè)置在Toolbar中,顯示方式有兩種:直接顯示在Toolbar中,顯示在overflow菜單中。顯示在overflow菜單中的按鈕,也可以通過手機的menu鍵來調(diào)出,如果當前Activity是隱藏狀態(tài)欄的,就需要使用menu鍵了。需要注意的是,手機的menu鍵只能調(diào)出包含在overflow里的item。
這里介紹一個特殊的方法,onPrepareOptionsMenu()。我們知道,創(chuàng)建OptionsMenu調(diào)用的方法是onCreateOptionsMenu,但是這個方法只會執(zhí)行一次。如果在運行過程中對OptionsMenu進行操作,比如改變ItemIcon等,這時候就要用到onPrepareOptionsMenu,這里方法中可以獲取到menu對象,對菜單欄進行操作。
onPrepareOptionsMenu通過invalidateOptionsMenu()方法調(diào)用。另外,點擊overflow按鈕也會調(diào)用onPrepareOptionsMenu,因為點擊overflow的時候,隱藏的menu item會顯示出來,也就是改變了menu的樣式,所以點擊overflow實際上已經(jīng)調(diào)用了invalidateOptionsMenu()方法。
ContextMenu
ContextMenu翻譯為上下文菜單,與OptionsMenu不同的是,ContextMenu是被view對象持有的,而OptionsMenu則是被Activity或者Fragment對象持有。
ContextMenu通過長按View調(diào)出。下面是一個長按Button彈出ContextMenu的例子:
- 創(chuàng)建menu的layout文件。當然這一步也可以省略,在代碼中CreateMenu的時候動態(tài)添加item是一樣的效果。
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:id="@+id/add_item"
android:icon="@drawable/ic_action_new"
android:title="Add"
app:showAsAction="ifRoom"
/>
<item
android:id="@+id/remo_item"
android:icon="@drawable/ic_action_remove"
android:title="Remove"
app:showAsAction="never"
/>
<item
android:id="@+id/more_item"
android:icon="@drawable/ic_action_more"
android:title="More"
app:showAsAction="never"
/>
</menu>
- 使用
registerForContextMenu方法,為目標View注冊上下文菜單,這里的例子是一個Button:
registerForContextMenu(mContButton);
- 創(chuàng)建上下文菜單,并設(shè)置監(jiān)聽:
@Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.toobar_menu,menu);
return super.onCreateOptionsMenu(menu);
}
@Override
public boolean onContextItemSelected(MenuItem item) {
switch (item.getItemId()){
case R.id.share_item:
Toast.makeText(this,"context menu add",Toast.LENGTH_SHORT).show();
}
return super.onContextItemSelected(item);
}
到這里一個簡單的上下文菜單功能就完成了。但是,實際使用的時候并不是這么簡單。比如Recyclerview是無法通過這種方式實現(xiàn)的。
Recyclerview的ContextMenu實現(xiàn)方式:
ContextMenu的創(chuàng)建是由長按事件引發(fā)的,所以View里也設(shè)置了一個onCreateContextMenuListener,Recyclerview可以通過它來實現(xiàn)ContextMenu。
使用onCreateContextMenuListener的方式也比較靈活,可以在RecyclerView.ViewHolder類中實現(xiàn)這個接口,對itemview設(shè)置onCreateContextMenuListener,也可以在adapter中的onBindViewHolder中設(shè)置。
下面看具體的例子,這是一個item為TextView的Recyclerview:
//Holder中對ItemView設(shè)置創(chuàng)建ContextMenu監(jiān)聽
private class RecycleHolder extends RecyclerView.ViewHolder{
public RecycleHolder(View itemView) {
super(itemView);
itemView.setOnCreateContextMenuListener(new View.OnCreateContextMenuListener() {
@Override
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.search_menu,menu);
}
});
}
//對ContextMenu的item設(shè)置響應
@Override
public boolean onContextItemSelected(MenuItem item) {
switch (item.getItemId()){
case R.id.share_item:
Toast.makeText(this,"context menu add",Toast.LENGTH_SHORT).show();
}
return super.onContextItemSelected(item);
}
這樣就完成了對Recyclerview的ContextMenu設(shè)置。如果我們還想要更高級的功能,比如對不同的Item彈出不同的Menu,要怎樣實現(xiàn)?
上面提到了,ContextMenu的創(chuàng)建實際上是監(jiān)聽了長按事件,我們可以同時對Item設(shè)置LongClickListener和CreateContextMenuListener,在LongClickListener中獲取當前item的position,然后傳遞給CreateContextMenuListener。注意,LongClickListener返回值應該設(shè)置為false,否則事件不會傳遞給CreateContextMenuListener
上面的代碼稍作修改:
//Holder 中不再設(shè)置監(jiān)聽
private class RecycleHolder extends RecyclerView.ViewHolder{
private TextView mTextView;
public RecycleHolder(View itemView) {
mTextView = (TextView) itemView;
}
}
private class RecycleAdapter extends RecyclerView.Adapter<LandViewActivity.RecycleHolder>
{
private id = -1;
@Override
public LandViewActivity.RecycleHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View TitleItemView = LayoutInflater.from(LandViewActivity.this).inflate(R.layout.item,parent,false);
return new LandViewActivity.RecycleHolder(TitleItemView);
}
@Override
public void onBindViewHolder(LandViewActivity.RecycleHolder holder, final int position) {
holder.mTextView.setText(mItems.get(position));
//對Recyclerview中的item設(shè)置長按監(jiān)聽,獲取到id,注意返回值為false
holder.mTextView.setOnLongClickListener(new View.OnLongClickListener() {
@Override
public boolean onLongClick(View v) {
id = position;
return false;
}
});
//對Recyclerview中的item設(shè)置創(chuàng)建菜單監(jiān)聽,根據(jù)id的值絕對是否創(chuàng)建菜單
holder.mTextView.setOnCreateContextMenuListener(new View.OnCreateContextMenuListener() {
@Override
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
MenuInflater inflater = getMenuInflater();
if (id%2==0) inflater.inflate(R.menu.search_menu,menu);
}
});
}
@Override
public int getItemCount() {
return mItems.size();
}
}
PopupMenu
PopupMenu是對某個View設(shè)置的彈出菜單,默認彈出在View的下方,如果控件不夠則彈出在上方,點擊該View 的時候就會彈出PopupMenu。
PopupMenu的定義如下:
mContButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//創(chuàng)建PopupMenu,并綁定到mContButton
PopupMenu popupMenu = new PopupMenu(LandViewActivity.this,mContButton);
MenuInflater menuInflater = getMenuInflater();
menuInflater.inflate(R.menu.toobar_menu, popupMenu.getMenu());
//popupMenu.inflate(R.menu.toobar_menu); API 14 可以采用這種方式
popupMenu.show();
//設(shè)置item的點擊事件
popupMenu.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
@Override
public boolean onMenuItemClick(MenuItem item) {
switch (item.getItemId()){
case R.id.add_item:
Toast.makeText(LandViewActivity.this,"Add button clicked",Toast.LENGTH_SHORT).show();
break;
case R.id.remo_item:
invalidateOptionsMenu();
Toast.makeText(LandViewActivity.this,"Remove button clicked",Toast.LENGTH_SHORT).show();
break;
case R.id.more_item:
Toast.makeText(LandViewActivity.this,"More button clicked",Toast.LENGTH_SHORT).show();
break;
default:
break;
}
return true;
}
});
}
});
PopupMenu的使用很簡單簡單,但是樣式修改比較麻煩,在menu文件里修改是不起作用的,只能通過theme的Style來修改:
在當前theme下添加以下Item:
<item name="android:dropDownListViewStyle">@style/MyListViewStyle</item>
<item name="android:textAppearanceLargePopupMenu">@style/PopupMenuText</item>
<item name="android:textAppearanceSmallPopupMenu">@style/PopupMenuText</item>
對應的Style:
<style name="PopupMenuText">
<item name="android:textColor">@color/colorBlack</item>
<item name="android:textSize">16sp</item>
</style>
<style name="MyListViewStyle">
<item name="android:divider">#F00</item>
<item name="android:dividerHeight">1px</item>
</style>