菜单是很多应用都会用到的组件,在Android系统中,菜单主要分为三类。选项菜单,上下文菜单,弹出菜单
一 选项菜单
选项菜单是Activity的主菜单项集合。提供对应用产生全局影响的操作,比如:"设置",''搜索"等
定义一个菜单,Android 推荐使用xml文件的方式来定义一个菜单。在项目的res/menu/目录内创建xml文件
<?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">
<item android:id="@+id/menu_option_id1"
android:title="标签1"
android:icon="@drawable/ic_action_name"
app:showAsAction="always"/>
<item android:id="@+id/menu_option_id2"
android:title="标签2"
app:showAsAction="never"/>
</menu>
<menu> 元素必须是该文件的根节点,可以包含一个或多个<item>和<group>元素
<item> 元素表示一个菜单项,该元素可包含嵌套的<menu>元素来创建子菜单,该元素支持多个属性
andorid:id 菜单项独有的资源ID,让应用能够在用户选择菜单项是识别该菜单项.
android:icon 菜单项的图标
android:title 菜单项标题(必须)
app:showAsAction 菜单项在应用栏中的显示方式
<group> 元素是不可见的容器,用该元素可以对菜单项进行分类,使同类元素的状态和可见性一致.
在Activity里面重写onCreateOpotionsMenu()方法.
override fun onCreateOptionsMenu(menu: Menu?): Boolean {
menuInflater.inflate(R.menu.menu_options, menu)
return true
}
当用户从选项菜单中选择菜单项时,Android 系统会回调onOptionsItemSelected()方法。我们可以通过菜单项的唯一ID来识别。
override fun onOptionsItemSelected(item: MenuItem): Boolean {
return when (item.itemId) {
R.id.menu_option_id1 -> {
Toast.makeText(this, "menu_option_id1", Toast.LENGTH_SHORT).show()
true
}
R.id.menu_option_id2 -> {
Toast.makeText(this, "menu_option_id2", Toast.LENGTH_SHORT).show()
true
}
else -> super.onOptionsItemSelected(item)
}
}
这样就可以弹出选项菜单和处理点击事件了。但是,默认的选项菜单会覆盖住Toolbar,如果我们想在Toolbar下面弹出选项菜单可以设置style。
<resources>
<!-- Base application theme. -->
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
<!-- Customize your theme here. -->
<item name="colorPrimary">@color/colorPrimary</item>
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
<item name="colorAccent">@color/colorAccent</item>
<item name="actionOverflowMenuStyle">@style/OverflowMenuStyle</item>
</style>
<style name="OverflowMenuStyle" parent="Widget.AppCompat.Light.PopupMenu.Overflow" >
<!--设置弹出位置,是否覆盖Toolbar,默认为true,即覆盖Toolbar-->
<item name="overlapAnchor">false</item>
<!--弹出层的背景颜色-->
<item name="android:popupBackground">#ffffff</item>
<!--弹出层水平方向上的偏移-->
<item name="android:dropDownHorizontalOffset">0dp</item>
<!--弹出层垂直方向上的偏移-->
<item name="android:dropDownVerticalOffset">0dp</item>
</style>
</resources>
有时,我们想在程序运行时更改一些菜单选项。我们可以重写onPrepareOptionsMenu()方法。在该方法中可以对菜单项做出一些修改,比如添加,移除,修改或禁用。程序在第一次启动时和后面每次显示菜单前都会调用此方法,我们可以根据是否需要修改的逻辑来修改菜单项。 如果菜单项在打开状态下需要更新的话,必须调用invalidateOptionsMenu()方法来请求系统调用onPrepareOptionsMenu()。下面的代码就是根据isNewTitle来动态更改菜单的标签
override fun onPrepareOptionsMenu(menu: Menu?): Boolean {
if (isNewTitle) {
menu?.findItem(R.id.menu_option_id2)?.title = "新标签"
} else {
menu?.findItem(R.id.menu_option_id2)?.title = "标签2"
}
return super.onPrepareOptionsMenu(menu)
}
二 上下文菜单
上下文菜单提供了很多操作,这些操作会影响界面中的特定的菜单项或上下文框架,任何视图都能拥有上下文菜单。
使用悬浮上下文菜单(类似对话框),当用户长按某个注册了上下文菜单的视图时,菜单会显示为一个悬浮列表。用户一次只能对一个菜单项执行关联操作。为视图注册上下文菜单请调用registerForContextMenu()将视图传递进去。创建悬浮的上下文菜单需要重写onCreateContextMenu()方法.
override fun onCreateContextMenu(menu: ContextMenu?, v: View?, menuInfo: ContextMenu.ContextMenuInfo?) {
super.onCreateContextMenu(menu, v, menuInfo)
menuInflater.inflate(R.menu.menu_context, menu)
}
当用户从悬浮的上下文菜单中选择菜单项时,系统会回调onContextItemSelected()方法
override fun onContextItemSelected(item: MenuItem): Boolean {
return when (item.itemId) {
R.id.menu_context_id1 -> {
Toast.makeText(this, "menu_context_id1", Toast.LENGTH_SHORT).show()
true
}
R.id.menu_context_id2 -> {
Toast.makeText(this, "menu_context_id2", Toast.LENGTH_SHORT).show()
true
}
R.id.menu_context_id3 -> {
Toast.makeText(this, "menu_context_id3", Toast.LENGTH_SHORT).show()
true
}
else -> super.onContextItemSelected(item)
}
}
三 弹出式菜单
弹出菜单是锚定在视图中的一种菜单,如果空间足够,它会显示在锚定视图的下方,否则显示在其上方.
创建一个弹出菜单需要实力化一个PopupMenu对象。创建该对象需要一个Context和应锚定菜单的Viewpopup
PopupMenu(this, btn2).apply {
setOnMenuItemClickListener { item ->
when (item.itemId) {
R.id.menu_popup_id1 -> {
Toast.makeText(this@MainActivity, "menu_popup_id1", Toast.LENGTH_SHORT).show()
true
}
R.id.menu_popup_id2 -> {
Toast.makeText(this@MainActivity, "menu_popup_id2", Toast.LENGTH_SHORT).show()
true
}
R.id.menu_popup_id3 -> {
Toast.makeText(this@MainActivity, "menu_popup_id3", Toast.LENGTH_SHORT).show()
true
}
else -> false
}
}
menuInflater.inflate(R.menu.menu_popup, menu)
show()
}
处理点击事件必须实现一个PopupMenu.OnMenuItemClickListener接口,通过setOnMenuItemClickListener()方法将其注册到PopupMenu。