如何在 TopAppBar 的布局中心对齐标题?

问题描述 投票:0回答:11
TopAppBar(
       backgroundColor = Color.Transparent,
       elevation = 0.dp,
       modifier= Modifier.fillMaxWidth(),
       navigationIcon = {
               IconButton(
                   onClick = { TODO },
                   enabled = true,
               ) {
                   Icon(
                       painter = painterResource(id = R.drawable.icon_back_arrow),
                       contentDescription = "Back",
                   )
               }
           }
       },
       title = {
           Text(
               modifier = if (action == null) Modifier.fillMaxWidth() else Modifier,
               textAlign = if (action == null) TextAlign.Center else TextAlign.Start,
               maxLines = 1,
               text = "Hello"
           )
       },
       actions = {
           action?.run {
               Text(
                   modifier = Modifier
                       .padding(horizontal = 16.dp)
                       .clickable(onClick = TODO),
                   color = Color.Green,
                   text ="Cancel",
               )
           }
       } 

我是 jetpack 的新手,如果 action 为空,我想将 TopAppBar 的标题居中对齐。标题未对齐布局中心。当没有 navigationIcon 时它工作但添加 navigationIcon 它显示稍微正确。我该怎么做才能在布局中心制作标题文本。

android android-jetpack-compose android-jetpack android-jetpack-compose-material3 android-compose-appbar
11个回答
26
投票

对于 Material2,您必须使用

TopAppBar
的其他构造函数,它没有预定义的内容插槽,允许您自定义内容内部的布局。

你可以这样做:

val appBarHorizontalPadding = 4.dp
val titleIconModifier = Modifier.fillMaxHeight()
    .width(72.dp - appBarHorizontalPadding)

TopAppBar(
    backgroundColor = Color.Transparent,
    elevation = 0.dp,
    modifier= Modifier.fillMaxWidth()) {

    //TopAppBar Content
    Box(Modifier.height(32.dp)) {

        //Navigation Icon 
        Row(titleIconModifier, verticalAlignment = Alignment.CenterVertically) {                
            CompositionLocalProvider(
                LocalContentAlpha provides ContentAlpha.high,
            ) {
                IconButton(
                    onClick = { },
                    enabled = true,
                ) {
                    Icon(
                        painter = painterResource(id = R.drawable.ic_add_24px),
                        contentDescription = "Back",
                    )
                }
            }
        }

        //Title
        Row(Modifier.fillMaxSize(),
            verticalAlignment = Alignment.CenterVertically) {

            ProvideTextStyle(value = MaterialTheme.typography.h6) {
                CompositionLocalProvider(
                    LocalContentAlpha provides ContentAlpha.high,
                ){
                    Text(
                        modifier = Modifier.fillMaxWidth(),
                        textAlign = TextAlign.Center,
                        maxLines = 1,
                        text = "Hello"
                    )
                }
            }
        }

        //actions
        CompositionLocalProvider(LocalContentAlpha provides ContentAlpha.medium) {
            Row(
                Modifier.fillMaxHeight(),
                horizontalArrangement = Arrangement.End,
                verticalAlignment = Alignment.CenterVertically,
                content = actions
            )
        }
    }
}


有了Material3,你可以简单地使用

CenterAlignedTopAppBar

CenterAlignedTopAppBar(
    title = { Text("Centered TopAppBar") },
    navigationIcon = {
        IconButton(onClick = { /* doSomething() */ }) {
            Icon(
                imageVector = Icons.Filled.Menu,
                contentDescription = "Localized description"
            )
        }
    }
)


7
投票

如果您使用的是 Material3,您也可以使用

CenterAlignedTopAppBar

fun CenterAlignedTopAppBar(
    title: @Composable () -> Unit,
    modifier: Modifier = Modifier,
    navigationIcon: @Composable () -> Unit = {},
    actions: @Composable RowScope.() -> Unit = {},
    colors: TopAppBarColors = TopAppBarDefaults.centerAlignedTopAppBarColors(),
    scrollBehavior: TopAppBarScrollBehavior? = null
) {
    SingleRowTopAppBar(
        modifier = modifier,
        title = title,
        titleTextStyle =
        MaterialTheme.typography.fromToken(TopAppBarSmallTokens.HeadlineFont),
        centeredTitle = true,
        navigationIcon = navigationIcon,
        actions = actions,
        colors = colors,
        scrollBehavior = scrollBehavior
    )
}

Center-aligned top app bar image


5
投票

编辑:旧答案已过时,请使用CenterAlignedTopAppBar

CenterAlignedTopAppBar(
    title = { Text(text = stringResource(id = titleRes)) },
    actions = {
        IconButton(onClick = onActionClick) {
            Icon(
                imageVector = actionIcon,
                contentDescription = actionIconContentDescription,
                tint = MaterialTheme.colorScheme.onSurface
            )
        }
    },
    colors = colors,
    modifier = modifier,
)

旧答案:

我重做了一些本地实现。

只需要做两件事:

1.将此文件添加到您的项目中。这是

TopAppBar
类的稍微修改的实现。 https://gist.github.com/evansgelist/aadcd633e9b160f9f634c16e99ffe163

2.将代码中的TopAppBar替换为CenterTopAppBar。这就是全部!

  Scaffold(
        topBar = {
            CenterTopAppBar(
                title = {
                    Text(
                        textAlign = TextAlign.Center,
                        text = text,
                    )
                },

编辑 分机代码

val Number.toPx
    get() = TypedValue.applyDimension(
        TypedValue.COMPLEX_UNIT_DIP,
        this.toFloat(),
        Resources.getSystem().displayMetrics
    )

结果


4
投票

标题居中的核心是左右占用槽位的空间是一样的。您只需要调整插槽的默认大小。我们给左右两个槽位默认占用空间的槽位,可以很好的解决这个问题,而且代码也很简单

@Composable
fun TopBar(title: Int, actions: @Composable (() -> Unit)? = null, popOnClick: () -> Unit) {

    val modifier = Modifier.size(width = 70.dp, height = 50.dp).background(Color.Red)

    TopAppBar(
        title = {
            Text(text = stringResource(id = title), fontSize = 16.sp,
             textAlign = TextAlign.Center, modifier = Modifier.fillMaxWidth()) },
        navigationIcon = {
            Box(modifier = modifier, contentAlignment = Alignment.Center) {
                IconButton(onClick = { popOnClick() }) {
                    Icon(Icons.Filled.ArrowBack, contentDescription = "", tint = MaterialTheme.colors.primary)
                }
            }
        },
        actions = {
            Box(modifier = modifier, contentAlignment = Alignment.Center) {
                if (actions != null) {
                    actions()
                }
            }
        },
        backgroundColor = MaterialTheme.colors.surface,
        elevation = 1.dp
    )
}



3
投票

这取决于应用栏中的内容。

如果你只有标题,那么你可以这样做:

topBar = {
        TopAppBar(content = {
            Text(
                modifier = Modifier.fillMaxWidth(),
                text = "Title Text",
                textAlign = TextAlign.Center,
                style = MaterialTheme.typography.h6,
            )
        })
    },

如果你的两边都有一个图标,你应该可以做同样的事情,如果一边有两个图标,另一边有两个图标,那么可能需要调整一些东西,然后可能想要使用添加一个相同大小的图标来平衡东西并启用假到它不可点击并且颜色透明所以它看不到,否则你可以尝试找出大小并在文本中添加填充结束,看来你还需要向透明图标添加 16.dp 填充,因为导航图标在标题之前有额外的填充,但在标题和操作之间没有填充

这是我为箭头图标和标题所做的

 topBar = {
        TopAppBar(
            navigationIcon = {
                IconButton(
                    onClick = {
                        navController.popBackStack()
                    }
                ) {
                    Icon(
                        imageVector = Icons.Default.ArrowBack,
                        contentDescription = "back arrow icon"
                    )
                }
            },
            title = {
                Text(
                    modifier = Modifier
                        .fillMaxWidth(),
                    text = "Basic Navigation",
                    textAlign = TextAlign.Center,
                )
            },
            actions = {
                IconButton(
                     modifier = Modifier
                        .padding(start = 16.dp),
                    enabled = false,
                    onClick = {}
                ) {
                    Icon(
                        imageVector = Icons.Default.ArrowBack,
                        contentDescription = "back arrow icon",
                        tint = Color.Transparent
                    )
                }
            }
        )
    }

0
投票

我只是 Jetpack Compose 的初学者,在我寻找该问题的解决方案之前,我试着想出自己的解决方案,也许对某些人来说就足够了。我需要 TopAppBar 的居中标题,只有左侧有导航图标,或者左右有两个图标,这个解决方案对我来说没问题。后来我配置为在右侧包含传递的图标或没有。

        TopAppBar(
            backgroundColor = Color.Green,
            elevation = 5.dp,
        ) {
            Row(
                modifier = Modifier.fillMaxWidth(),
                horizontalArrangement = Arrangement.SpaceBetween,
                verticalAlignment = Alignment.CenterVertically
            ) {
                // size of an icon and placeholder box on the right side
                val iconSize = 32.dp

                Icon(
                    imageVector = Icons.Default.ArrowBack,
                    contentDescription = "Arrow Back",
                    modifier = Modifier
                        .clickable {
                            navController.popBackStack()
                        }
                        .size(iconSize)
                )
                Text(text = "Centered Title", fontSize = 32.sp)
                // placeholder on the right side in order to have centered title - might be replaced with icon
                Box(
                    modifier = Modifier
                        .size(iconSize)
                ) { }
            }

我无法附上截图,预览在这里:https://i.stack.imgur.com/UNQTF.png


0
投票

如果您使用的是 Material 2,我找到了一个很好的解决方法。 创建一行,其中包含:

  • 权重为 1 的列,包含一个图标
  • 权重为 1
  • 的列,包含标题
  • weight 1
  • 的垫片
  • 设备的屏幕会自动分成3等份。 这是一个代码示例:

Scaffold( topBar = { TopAppBar( backgroundColor = Transparent, elevation = 0.dp, modifier = Modifier.fillMaxWidth() ) { /** TopAppBar Content */ Row( modifier = Modifier.height(51.dp).fillMaxWidth(), verticalAlignment = Alignment.CenterVertically ) { /** Icon*/ Column(modifier = Modifier.weight(1f).padding(start = 9.dp)) { IconButton( onClick = { /*TODO*/ }, modifier = Modifier .width(22.dp) .height(22.dp), enabled = true, ) { Icon( painter = painterResource(id = R.drawable.ic_baseline_arrow_back), contentDescription = "Back", tint = ThemeBlue ) } } /** Header */ Column(modifier = Modifier.weight(1f)) { Text( modifier = Modifier.fillMaxWidth(), style = MaterialTheme.typography.h1, textAlign = TextAlign.Center, maxLines = 1, text = "Header", ) } /*TODO * When the stable version of Material 3 comes out * we should replace the whole TopAppBar with CenterAlignedTopAppBar. * For now, this Spacer keeps the Header component in the center of the topBar */ Spacer(modifier = Modifier.weight(1f)) } } }, content = { Divider(color = ThemeBlue, thickness = 0.5.dp) } )

这里是这段代码产生的结果的截图:


0
投票

TopAppBar( title = { Text( text = screenname, modifier = Modifier .fillMaxWidth() .wrapContentWidth(align= Alignment.CenterHorizontally) ) }, modifier = modifier )



0
投票


-1
投票


-3
投票

title = { Text( text = "title", textAlign = TextAlign.Center, modifier = Modifier.fillMaxWidth() ) }

© www.soinside.com 2019 - 2024. All rights reserved.