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

时间:2020-12-19 19:25:06

标签: 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))
}

我只希望工具栏菜单中的一个图标可见,其他图标添加到溢出菜单中,就像使用 app:showAsAction="never" 使用 xml 完成的那样

<item
    android:id="@+id/action_sign_out"
    android:title="@string/toolbar_sign_out"
    app:showAsAction="never"/>

3 个答案:

答案 0 :(得分:4)

受到 @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)
        }
    )
}

预览看起来像这样

Navigation hamburger, "App bar" title, phone icon, send icon, three vertical dots overflow menu

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

答案 1 :(得分:3)

您必须自己提供 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)
                }
            }
        }
    )
}

编辑:针对 Compose 1.0.0-beta08 进行了更新

答案 2 :(得分:0)

我稍微修改了@jns 的答案,使其更加模块化和可重用。 这是可重用的溢出菜单:

@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()
    }
}

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

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

如果需要,我们可以向 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*/ })
            }
        }
    )

.

@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))
    }
}