android 在Material 3 TopAppBar代码中的何处定义了填充?

dced5bon  于 2023-04-18  发布在  Android
关注(0)|答案(1)|浏览(114)

我知道Material 3中的TopAppBar有一个16 dp的左/右填充。但是我想知道在源代码中定义了什么?例如,TopAppBar构造函数看起来像这样-没有提示默认的左/右填充。

@ExperimentalMaterial3Api
@Composable
fun TopAppBar(
    title: @Composable () -> Unit,
    modifier: Modifier = Modifier,
    navigationIcon: @Composable () -> Unit = {},
    actions: @Composable RowScope.() -> Unit = {},
    windowInsets: WindowInsets = TopAppBarDefaults.windowInsets,
    colors: TopAppBarColors = TopAppBarDefaults.topAppBarColors(),
    scrollBehavior: TopAppBarScrollBehavior? = null
) {
    SingleRowTopAppBar(
        modifier = modifier,
        title = title,
        titleTextStyle = MaterialTheme.typography.fromToken(TopAppBarSmallTokens.HeadlineFont),
        centeredTitle = false,
        navigationIcon = navigationIcon,
        actions = actions,
        windowInsets = windowInsets,
        colors = colors,
        scrollBehavior = scrollBehavior
    )
}

是否有任何常量可以用来将这个填充应用到其他组件,或者我必须硬编码16 dp?我希望TopAppBar下面的东西具有相同的左/右填充,否则它看起来不一致。

yks3o0rb

yks3o0rb1#

它在TopAppBarLayout组合中的调用链中进一步定义,在titlePlaceable.placeRelative部分中。
下面是相关的代码部分

Box(
    Modifier
        .layoutId("navigationIcon")
        .padding(start = TopAppBarHorizontalPadding) // <-- line of interest
) {
    CompositionLocalProvider(
        LocalContentColor provides navigationIconContentColor,
        content = navigationIcon
    )
}
Box(
    Modifier
        .layoutId("title")
        .padding(horizontal = TopAppBarHorizontalPadding) // <-- line of interest
        // ...
) {
    ProvideTextStyle(value = titleTextStyle) {
        CompositionLocalProvider(
            LocalContentColor provides titleContentColor.copy(alpha = titleAlpha),
            content = title
        )
    }
}
layout(constraints.maxWidth, layoutHeight) {
    // Navigation icon
    navigationIconPlaceable.placeRelative(
        x = 0,
        y = (layoutHeight - navigationIconPlaceable.height) / 2
    )
    // Title
    titlePlaceable.placeRelative(
        x = when (titleHorizontalArrangement) {
            Arrangement.Center -> (constraints.maxWidth - titlePlaceable.width) / 2
            Arrangement.End ->
                constraints.maxWidth - titlePlaceable.width - actionIconsPlaceable.width
            // Arrangement.Start.
            // An TopAppBarTitleInset will make sure the title is offset in case the
            // navigation icon is missing.
            else -> max(TopAppBarTitleInset.roundToPx(), navigationIconPlaceable.width)
        },
    // ...

这是上面代码中使用的值

private val TopAppBarHorizontalPadding = 4.dp
private val TopAppBarTitleInset = 16.dp - TopAppBarHorizontalPadding

这些被定义为库的一部分,所以它们基本上是常量,并且不太可能在版本之间改变。即使它们发生了变化,您也可以控制何时更新库,并且在那时您也可以更新您的填充以再次匹配。
因此,当顶部应用栏不显示导航图标时,start侧的填充是12.dp,然后是标题Box,它有自己的填充4.dp,总共有16.dp的填充。
当顶部栏确实显示导航图标时,start侧的填充为0.dp,然后导航图标Box跟随,其具有其自己的填充4.dp,总共有4.dp的填充。通常,导航图标是通过使用IconButton并将Icon作为内容添加到其中来添加的。IconButton的(触摸)大小为48.dp(在IconButton组合中定义),默认的Icon大小是24.dp。这意味着即使实际的填充是4.dp,“视觉”填充到Icon的一侧是4.dp + (48.dp / 2 - 24.dp / 2) = 4.dp + 12.dp = 16.dp
end侧,操作图标所在的位置或标题结束的位置(当没有操作图标时)也是类似的。
因此,在这两种情况下(只要你使用默认的图标大小),“视觉”填充是相同的16.dp。因此,如果你决定为你的内容使用16.dp的填充,布局将看起来对齐。
请注意,所有这些都假设左/右windowInsets为0,这可能不是所有设备和所有方向的情况。
因此,为了确保布局在所有情况下看起来都对齐,您还需要在布局中考虑windowInsets。如果您已经这样做了,那么当您添加16.dp的填充时,事情应该正确对齐。如果您没有,然后你需要将windowInsets应用于你(父)可组合的(这应该是最简单的选择)或者您需要通过调用calculateLeftPaddingcalculateRightPaddingwindowInsets添加到基于LayoutDirection的正确侧的计算中。

val ld = LocalLayoutDirection.current
val insets = windowInsets.asPaddingValues(LocalDensity.current)
val leftPadding = insets.calculateLeftPadding(ld)
val rightPadding = insets.calculateRightPadding(ld)

相关问题