一、Menu概述
1、Android3.0之前的menu
在Android3.0, 当用户按"菜单"按钮时,选项菜单的内容会出现在屏幕底部,可以包含多达6个菜单项,超出部分则以“更多”来显示
2、Android3.0之后的menu
在Android3.0及更高版本的系统中,选项菜单中的项目将出现在操作栏中,用户可以使用操作栏右侧的图标或者按设备的菜单键显示操作溢出菜单。
3、menu的分类
- 选项菜单(OptionMenu)
- 上下文菜单(ContextMenu)
- 弹出菜单(PopupMenu)
二、Menu的使用
1、选项菜单 OptionMenu
选项菜单是一个应用的主菜单项,用于放置对应用产生全局影响的操作。
创建Menu
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<!-- showAsAction属性值: always 直接在标题栏显示, never 不显示
withText:控制图标和文本一起显示
ifRoom: 有空间就显示 -->
<item android:title="保存"
android:id="@+id/save"
android:icon="@mipmap/ic_launcher"
app:showAsAction="always"/>
<item android:title="设置"
android:id="@+id/setting"/>
<item android:title="更多操作" >
<menu >
<item android:title="退出"
android:id="@+id/exit"/>
<item android:title="子菜单2" />
<item android:title="子菜单3" />
</menu>
</item>
</menu>
package com.example.testapplication;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import android.content.Intent;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;
public class MainActivity extends AppCompatActivity {
private static final String TAG = "TestMain";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
// 创建OptionMenu
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// 加载资源菜单
getMenuInflater().inflate(R.menu.option, menu);
return true;
}
// OptionMenu菜单项的选中方法
@Override
public boolean onOptionsItemSelected(@NonNull MenuItem item) {
switch (item.getItemId()){
case R.id.save:
Toast.makeText(this, "保存", Toast.LENGTH_SHORT).show();
break;
case R.id.setting:
Toast.makeText(this, "设置", Toast.LENGTH_SHORT).show();
break;
case R.id.exit:
finish();
break;
}
return super.onOptionsItemSelected(item);
}
}
2、ContextMenu
长按某个view不放, 就会在屏幕中间弹出ContextMenu
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="@+id/delete"
android:title="删除" />
<item
android:id="@+id/opera1"
android:title="重命名" />
</menu>
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//1、注册
registerForContextMenu(findViewById(R.id.button));
//2、创建 覆盖onCreateContextMenu
}
@Override
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
getMenuInflater().inflate(R.menu.context, menu);
}
@Override
public boolean onContextItemSelected(@NonNull MenuItem item) {
switch (item.getItemId()){
case R.id.delete:
Toast.makeText(this, "删除", Toast.LENGTH_SHORT).show();
break;
case R.id.opera1:
Toast.makeText(this, "重命名", Toast.LENGTH_SHORT).show();
break;
}
return super.onContextItemSelected(item);
}
上下文模式
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//1、注册
registerForContextMenu(findViewById(R.id.button));
//2、创建 覆盖onCreateContextMenu
//3、菜单项的操作 覆盖onContextItemSelected
//4、为按钮设置上下文操作模式
//a、实现ActionMode CallBack
//b、在view的长按事件中去启动上下文操作模式
findViewById(R.id.button).setOnLongClickListener(new View.OnLongClickListener(){
@Override
public boolean onLongClick(View view) {
startActionMode(cb);
return false;
}
});
}
ActionMode.Callback cb = new ActionMode.Callback() {
@Override
public boolean onCreateActionMode(ActionMode actionMode, Menu menu) {
Log.i(TAG, "创建");
getMenuInflater().inflate(R.menu.context, menu);
return true;
}
@Override
public boolean onPrepareActionMode(ActionMode actionMode, Menu menu) {
Log.i(TAG, "准备");
return false;
}
@Override
public boolean onActionItemClicked(ActionMode actionMode, MenuItem menuItem) {
Log.i(TAG, "点击");
switch (menuItem.getItemId()){
case R.id.delete:
Toast.makeText(MainActivity.this, "删除", Toast.LENGTH_SHORT).show();
break;
case R.id.opera1:
Toast.makeText(MainActivity.this, "重命名", Toast.LENGTH_SHORT).show();
break;
}
return true;
}
// 上下文操作结束时被调用
@Override
public void onDestroyActionMode(ActionMode actionMode) {
Log.i(TAG, "结束");
}
};
3、PopupMenu
一个模态形式展示出的弹出风格菜单,绑在某个View上,一般出现在被绑定的View的下方
//popup_btn:演示PopupMenu
final Button popupBtn = findViewById(R.id.popup_btn);
popupBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
//①实例化PopupMenu对象 (参数2:被锚定的view)
final PopupMenu menu = new PopupMenu(MainActivity.this,popupBtn);
//②加载菜单资源:利用MenuInflater将Menu资源加载到PopupMenu.getMenu()所返回的Menu对象中
//将R.menu.xx对于的菜单资源加载到弹出式菜单中
menu.getMenuInflater().inflate(R.menu.popup,menu.getMenu());
//③为PopupMenu设置点击监听器
menu.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
@Override
public boolean onMenuItemClick(MenuItem menuItem) {
switch (menuItem.getItemId()){
case R.id.copy:
Toast.makeText(MainActivity.this,"复制",Toast.LENGTH_SHORT).show();
break;
case R.id.paste:
Toast.makeText(MainActivity.this,"粘贴",Toast.LENGTH_SHORT).show();
break;
}
return false;
}
});
//④千万不要忘记这一步,显示PopupMenu
menu.show();
}
});
三、常见问题与经验分享
1、xml定义menu的优势
- 清晰的菜单结构
- 将菜单内容与应用的逻辑代码分离
- 资源适配更容易
2、xml定义的menu不显示
- onCreateOptionsMenu() 方法必须返回true
- onOptionsItemSelected() 方法返回true
- 调用父类默认实现
坐得住板凳,耐得住寂寞,守得住初心!