Android中菜单类型之间的区别和设计指南

227 阅读8分钟

安卓中不同类型的菜单

菜单是基本的用户界面元素,经常被用来保存那些可能被埋没的操作。

这些隐藏的元素可以通过以下方式访问。

  • 点击一个按钮。
  • 使用手势,如长按一个图像。

将菜单作为用户界面组件的原因

  • 释放屏幕空间。
  • 执行那些不直接出现在屏幕上的用户所需要的大部分操作。
  • 提供一种能力,允许转移到应用程序的各个部分,这些部分在有用户界面显示的情况下不容易使用。

前提条件

要学习本教程,读者需要:

  • 在你的机器上安装有Android Studio。
  • 对Kotlin编程语言有基本了解。
  • 具备Android应用开发的基本知识。

Android中使用的菜单类型

根据应用程序的不同背景和内容,使用不同类型的菜单。以下是各种类型的菜单。

选项菜单

选项菜单是呈现与应用程序的当前活动或上下文直接相关的操作和其他选项的菜单。下面是一些选择菜单的例子。

  • 设置
  • 分享
  • 搜索
  • 复制链接
  • 帮助
  • 历史记录
  • 隐私

Options menu

创建选项菜单

在资源文件夹中,创建一个菜单目录,并在该目录中创建一个选项菜单文件,包括以下代码来建立你的菜单项。

<menu xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto">

        <item
            android:id="@+id/settings"
            android:icon="@drawable/ic_baseline_settings_24"
            android:title="Settings"
            app:showAsAction="always" />

        <item
            android:id="@+id/share"
            android:title="Share"
            />

        <item
            android:id="@+id/history"
            android:title="History"
            />

        <item
            android:id="@+id/help"
            android:title="Help"
            />

        <item
            android:id="@+id/logout"
            android:title="logout"
            />
</menu>

解释

  • <menu> - 这是一个元素,为创建菜单项和组提供基础。
  • <item> - 项目是用来表示要在菜单中显示的单一元素。它提供了建立多个菜单项的能力。
  • <group> - 组允许你对菜单项目进行分类,据说这些项目共享相同的属性,例如活动状态和可见性。

处理对菜单项的点击

为了处理对菜单项的点击,你首先需要对菜单资源文件进行充气。

override fun onCreateOptionsMenu(menu: Menu?): Boolean {
    menuInflater.inflate(R.menu.options_menus, menu)
    return true
}

onOptionsItemSelected 方法处理菜单内的每个元素以及点击时要执行的操作。

//handling click events in an options menu items click

override fun onOptionsItemSelected(item: MenuItem): Boolean {
    when (item.itemId) {
        R.id.settings -> {
            Toast.makeText(this, "This is settings", Toast.LENGTH_SHORT).show()
            return true
        }
        R.id.share -> {
            Toast.makeText(this, "This is share", Toast.LENGTH_SHORT).show()
            return true
        }
        R.id.history -> {
            Toast.makeText(this, "This is history", Toast.LENGTH_SHORT).show()
            return true
        }
        R.id.help -> {
            Toast.makeText(this, "This is is help", Toast.LENGTH_SHORT).show()
            return true
        }
        R.id.logout -> {
            Toast.makeText(this, "logged out", Toast.LENGTH_SHORT).show()
            return true
        }
        else -> {
            return super.onOptionsItemSelected(item)
        }
    }
}

when 语句用于评估itemId 的值。如果它的值等于R.id.<item_id> 的值,Toast.makeText 方法就会被调用,并显示出被点击的项目的信息。这表明菜单正在工作。因此我们可以执行所需的操作。

上下文菜单

当与某一项目或上下文框架相关的操作在当前屏幕上呈现时,就会利用上下文菜单。这种菜单的例子是在人们长按一张图片时显示的。

上下文菜单有两种类型。

  • 浮动的上下文菜单。
  • 上下文动作菜单。

浮动的上下文菜单

当一个人长按(按住)一个项目时,这个菜单会作为一个浮动的菜单项目列表出现。应该声明对浮动上下文菜单的支持。这个菜单允许一次对一个项目进行操作。

处理对浮动的上下文菜单项目的点击

就像选项菜单一样,浮动上下文菜单的点击监听器也需要被处理,以提供用户需要的相关和适当的操作。

这个点击监听器在菜单创建后在下面的方法中处理。

 //Float contextual menu
override fun onCreateContextMenu(
    menu: ContextMenu?,
    v: View?,
    menuInfo: ContextMenu.ContextMenuInfo?
) {
    super.onCreateContextMenu(menu, v, menuInfo)
    menuInflater.inflate(R.menu.float_contextual_menu, menu)
}

下面的方法处理浮动上下文菜单的点击。

//handling click events in an float context menu items clicks
override fun onContextItemSelected(item: MenuItem): Boolean {
    when (item.itemId) {
        R.id.color -> {
            var textView = findViewById<TextView>(R.id.textHappyCoding)
            textView.setTextColor(Color.parseColor("#FF0000"))
            Toast.makeText(this, "color changed", Toast.LENGTH_SHORT).show()
            return true
        }
        R.id.font -> {
            var textView = findViewById<TextView>(R.id.textHappyCoding)
            textView.setTextSize(TypedValue.COMPLEX_UNIT_PX, 32F)
            Toast.makeText(this, "size increased", Toast.LENGTH_SHORT).show()

            return true
        }
        else -> {
            return super.onContextItemSelected(item)
        }
    }
}

Floating contextual menu

上下文动作菜单

这是一种上下文菜单,通常用于显示基于长点击项的操作。有几种方法经常被用来操作上下文操作模式的菜单。这些方法解释如下。

第一种方法是用来创建上下文操作模式菜单的。

private val mActionCallback = object : ActionMode.Callback {
    override fun onCreateActionMode(mode: ActionMode, menu: Menu): Boolean {
        // assuming we have a menu resource file named actionmode_contextual_menu
        menuInflater.inflate(R.menu.actionmode_contextual_menu, menu)
        return true
    }

为了准备上下文操作模式菜单,我们可以使用下面这个方法来执行该操作。

override fun onPrepareActionMode(mode: ActionMode, menu: Menu): Boolean {
        return false
    }

还有一个方法是用来更新动作模式菜单,甚至在需要时更新操作。

override fun onDestroyActionMode(mode: ActionMode) {
        //perform any update you will require
    }

为了处理动作模式的点击并在每个菜单项上实现所需的操作,使用了下面的代码。

override fun onActionItemClicked(mode: ActionMode, item: MenuItem): Boolean {
            return when (item.itemId) {
                R.id.name -> {
                    Toast.makeText(this@MainActivity, "Name selected", Toast.LENGTH_SHORT).show()
                    mode.finish()
                    return true
                }
                R.id.description -> {
                    Toast.makeText(this@MainActivity, "This is description", Toast.LENGTH_SHORT).show()
                    mode.finish()
                    return true
                }
                else -> false
            }
        }

Action mode

上下文动作模式菜单与浮动式上下文菜单的区别

  • 与浮动的上下文菜单不同,上下文动作模式在屏幕的顶部显示影响所选项目的动作和操作栏。
  • 上下文操作模式菜单给人一种同时对多个项目执行各种操作的能力。例如,人们可以选择多个项目并执行一个删除操作。

弹出式菜单

这些菜单类似于浮动的上下文菜单,它和浮动的上下文菜单一样,在一个浮动的对话框中包含了行动和操作。

弹出式菜单与浮动的上下文菜单不同,它们不改变所选择的项目,并被用来提供更广泛的菜单操作集。

fun showPopupMenu(view: View) {
    val popup = PopupMenu(this, view)
    popup.setOnMenuItemClickListener(this)
    popup.inflate(R.menu.popup_menu)
    popup.show()
}

为了膨胀和处理弹出式菜单的点击,采用了以下方法。

override fun onMenuItemClick(item: MenuItem): Boolean {
    return when (item.itemId) {
        R.id.background -> {
            var background = findViewById<ConstraintLayout>(R.id.layoutBackground)
            background.setBackgroundColor(Color.parseColor("#3c3f41"))
            true
        }
        R.id.description -> {
            var textView = findViewById<TextView>(R.id.textHappyCoding)
            textView.text = "From Hello world to changing the world"
            true
        }
        R.id.delete -> {
            var textView = findViewById<TextView>(R.id.textHappyCoding)
            textView.text = ""
            true
        }
        else -> false
    }
}

Pop up menu

可检查的菜单

可检查菜单经常被用来执行特定的任务,如激活和停用功能。对于几个可执行的动作,可以使用一个复选框或一个单选按钮。

一个可检查的菜单可以设计如下。创建一个菜单资源文件并添加以下元素。

<menu xmlns:android="http://schemas.android.com/apk/res/android">

    <group android:checkableBehavior="single">
        <item
            android:id="@+id/checkbox"
            android:title="checkable_one" android:checked="false"/>
        <item
            android:id="@+id/checkbox2"
            android:title="checkable_two"
            android:checked="false"/>
        <item
            android:id="@+id/checkbox3"
            android:title="checkable_three"
            android:checked="false"/>
    </group>
    <group android:id="@+id/intent_based">

    </group>

</menu>

解释

checkablebehaviour 是一个属性,可以用来表示可检查菜单项上的检查行为和动作。它可以通过以下方式指定。

  • all - 用于表明可以选择所有的选项,并使用一个复选框来促进这一操作。
  • single - 用来表示只可以挑选一个项目,单选按钮用来做这个操作。
  • none - 它用来表示没有选择任何菜单项。

就像选项菜单一样,可选菜单的点击监听器也在onOptionsItemSelected 方法中处理,如下图所示。

override fun onOptionsItemSelected(item: MenuItem): Boolean {
        item.isChecked = !item.isChecked
        return when (item.itemId) {
            R.id.checkbox -> {
                Toast.makeText(this, "checkable_one", Toast.LENGTH_SHORT).show()
                true
            }
            R.id.checkbox2 -> {
                Toast.makeText(this, "checkable_Two", Toast.LENGTH_SHORT).show()
                true
            }
            R.id.checkbox3 -> {
                Toast.makeText(this, "checkable_Three", Toast.LENGTH_SHORT).show()
                true
            }
            else -> false
        }
    }

Checkable menu

如果一个菜单项被点击,首先会检查它是否被选中,然后使用这个代码更新item.isChecked = !item.isChecked

基于意图的菜单

与基于意图的菜单相反,其他菜单是使用菜单资源文件痛快地创建的。基于意图的菜单是根据应用动态地添加的。

在可检查的菜单资源文件内添加以下实现,它被用作基于意图的菜单项。

<group android:id="@+id/intent_based">

</group>

然后在onCreateOptionsMenu 方法内,添加下面的实现来整合基于意图的菜单。

//Intent based menu
val  intent= Intent(android.content.Intent.ACTION_SEND)
intent.setType("text/plain")
intent.putExtra(android.content.Intent.EXTRA_TEXT,"Hello am intent based menu")

menu!!.addIntentOptions(
    R.id.intent_based, 0, 0, this.componentName, null, intent, 0, null
)

菜单的设计指南和最佳实践

基于不同类型的菜单,有一些设计准则和最佳实践需要遵循。

  • 发布命令的最佳位置。想一想这个命令以及它是如何执行其动作的。它是适用于特定的选择还是整个活动?
  • 菜单项的排序。在安排菜单项时,把经常使用的、首先使用的动作放在前面。
  • 菜单项的可恢复性。不要把菜单项放置在用户不能通过长按屏幕上的特定项目来随时访问上下文或弹出式菜单的地方。
  • 第一个上下文菜单项目。第一个上下文菜单选项应该总是选择最直接的操作,比如说,打开。
  • 用上下文菜单识别选定的项目。这总是在弹出式或行动模式的帮助下完成的,在这一点上应该照顾到用户所选择的项目。否则,用户很可能会忘记。因此,识别所选项目以提供一个上下文菜单是合适的。这样做有助于用户回忆起他们要执行的操作。
  • 固定最重要的命令。这一点在选择菜单上是通过在菜单项上放置一个图标来完成的,以保证它总是固定的,并能被用户访问,如下图所示。
<item
    android:id="@+id/settings"
    android:icon="@drawable/ic_baseline_settings_24"
    android:title="Settings"
    app:showAsAction="always" />

结论

在这篇文章中,我们已经了解了Android中使用的菜单,不同类型的菜单,菜单类型之间的区别和设计指南,以及处理菜单时的最佳实践。