如何使用 Jetpack Compose 创建带有溢出菜单的工具栏?

Thr*_*ian 4 android android-jetpack-compose

在 Compose 中,Toolbar 的菜单图标如何变成溢出?

Scaffold(
    topBar = {
        TopAppBar(
            title = {
                Text(text = "LayoutsCodelab")
            },
            actions = {
                IconButton(onClick = { /* doSomething() */ }) {
                    Icon(Icons.Filled.Favorite)
                }

                IconButton(onClick = { /* doSomething() */ }) {
                    Icon(Icons.Filled.Refresh)
                }

                IconButton(
                    onClick = { /* doSomething() */ }) {
                    Icon(Icons.Filled.Call)
                }

            }
        )
    },
    bottomBar = {
        BottomNavigationLayout()
    }
) { innerPadding ->
    PhotoCard(Modifier.padding(innerPadding))
}
Run Code Online (Sandbox Code Playgroud)

我只希望工具栏菜单中的一个图标可见 app:showAsAction="never"

<item
    android:id="@+id/action_sign_out"
    android:title="@string/toolbar_sign_out"
    app:showAsAction="never"/>
Run Code Online (Sandbox Code Playgroud)

Oya*_*nlı 24

我修改了一些 @jns 的答案,使其更加模块化和可重用。这是可重用的 OverflowMenu:

@Composable
fun OverflowMenu(content: @Composable () -> Unit) {
    var showMenu by remember { mutableStateOf(false) }

    IconButton(onClick = {
        showMenu = !showMenu
    }) {
        Icon(
            imageVector = Icons.Outlined.MoreVert,
            contentDescription = stringResource(R.string.more),
        )
    }
    DropdownMenu(
        expanded = showMenu,
        onDismissRequest = { showMenu = false }
    ) {
        content()
    }
}
Run Code Online (Sandbox Code Playgroud)

这就是它在 TopAppBar 中的使用方式:

TopAppBar(
        title = {
            Text(text = stringResource(R.string.my_title))
        },
        actions = {
            OverflowMenu {
                DropdownMenuItem(onClick = { /*TODO*/ }) {
                    Text("Settings")
                }
                DropdownMenuItem(onClick = { /*TODO*/ }) {
                    Text("Bookmarks")
                }
            }
        }
    )
Run Code Online (Sandbox Code Playgroud)

如果需要,我们可以向 DropDownMenuItems 添加图标。这些项目也可以提取为可重用的可组合项。如果您希望在菜单上显示其他操作按钮(即显示为操作),则应将它们放在 OverflowMenu 之前。

TopAppBar(
        title = {
            Text(text = stringResource(R.string.bookmark))
        },
        actions = {
            //This icon will be shown on the top bar, on the left of the overflow menu
            IconButton(onClick = { /*TODO*/ }) {
                Icon(Icons.Filled.FavoriteBorder, stringResource(R.string.cd_favorite_item))
            }
            OverflowMenu {
                SettingsDropDownItem(onClick = { /*TODO*/ })
                BookmarksDropDownItem(onClick = { /*TODO*/ })
            }
        }
    )
Run Code Online (Sandbox Code Playgroud)

@Composable
   fun SettingsDropDownItem(onClick : () -> Unit) {
      //Drop down menu item with an icon on its left
      DropdownMenuItem(onClick = onClick) {
         Icon(Icons.Filled.Settings,
            contentDescription = stringResource(R.string.settings),
            modifier = Modifier.size(24.dp))
         Spacer(modifier = Modifier.width(8.dp))
         Text(stringResource(R.string.settings))
     }
  }

  @Composable
  fun BookmarksDropDownItem(onClick : () -> Unit) {
     //Drop down menu item with an icon on its left
     DropdownMenuItem(onClick = onClick) {
        Icon(painter = painterResource(R.drawable.ic_bookmark_filled),
            contentDescription = stringResource(R.string.bookmark),
            modifier = Modifier.size(24.dp))
        Spacer(modifier = Modifier.width(8.dp))
        Text(stringResource(R.string.bookmark))
    }
}
Run Code Online (Sandbox Code Playgroud)


mac*_*our 13

受到@jns答案的启发,我制作了一个ActionMenu可组合项,它采用对象列表ActionItemSpec。并在必要时用溢出菜单显示它们。我对它的建模ActionItemSpec有点像旧的 XML 菜单项条目,但添加了一个 onClick lambda。

它是这样使用的

@Preview
@Composable
fun PreviewActionMenu() {
    val items = listOf(
        ActionItemSpec("Call", Icons.Default.Call, ActionItemMode.ALWAYS_SHOW) {},
        ActionItemSpec("Send", Icons.Default.Send, ActionItemMode.IF_ROOM) {},
        ActionItemSpec("Email", Icons.Default.Email, ActionItemMode.IF_ROOM) {},
        ActionItemSpec("Delete", Icons.Default.Delete, ActionItemMode.IF_ROOM) {},
    )
    TopAppBar(
        title = { Text("App bar") },
        navigationIcon = {
            IconButton(onClick = {}) {
                Icon(Icons.Default.Menu, "Menu")
            }
        },
        actions = {
            // show 3 icons including overflow
            ActionMenu(items, defaultIconSpace = 3)
        }
    )
}

Run Code Online (Sandbox Code Playgroud)

预览看起来像这样

导航汉堡、“应用栏”标题、电话图标、发送图标、三个垂直点溢出菜单

完整的粘贴在这里: https: //gist.github.com/MachFour/369ebb56a66e2f583ebfb988dda2decf

  • 干得好马赫福。可能需要稍微调整一下,使用 ActionMenu 内容的 DSL 样式定义:“ActionMenu(...) { ActionItemSpec(...) ActionItemSpec(...) ... }”。 (2认同)

jns*_*jns 6

您必须自己提供 OverFlowMenu,例如:

@Preview
@Composable
fun PreviewOverflowMenu() {
    OverflowMenuTest()
}

@Composable
fun OverflowMenuTest() {
    var showMenu by remember { mutableStateOf(false) }

    TopAppBar(
        title = { Text("Title") },
        actions = {
            IconButton(onClick = { /*TODO*/ }) {
                Icon(Icons.Default.Favorite)
            }
            IconButton(onClick = { showMenu = !showMenu }) {
                Icon(Icons.Default.MoreVert)
            }
            DropdownMenu(
                expanded = showMenu,
                onDismissRequest = { showMenu = false }
            ) {
                DropdownMenuItem(onClick = { /*TODO*/ }) {
                    Icon(Icons.Filled.Refresh)
                }
                DropdownMenuItem(onClick = { /*TODO*/ }) {
                    Icon(Icons.Filled.Call)
                }
            }
        }
    )
}
Run Code Online (Sandbox Code Playgroud)

编辑:针对 Compose 1.0.0-beta08 更新