如何单独修改Material3 MediumTopAppBar的大标题TextStyle?
问题描述
使用Material3的MediumTopAppBar时,尝试修改大标题的TextStyle但不影响小标题样式。当前实现代码如下:
MediumTopAppBar( title = { HeadlineLargeBlackText(text = "pageTitle") }, navigationIcon = { IconButton(onClick = { onBackPressed.invoke() }) { Icon( imageVector = Icons.Filled.ArrowBack, contentDescription = stringResource(id = R.string.action_back) ) } }, scrollBehavior = scrollBehavior )
但设置HeadlineLargeBlackText后,大、小标题的TextStyle均被修改,导致两者样式一致。需求是大标题为自定义大样式,小标题保持默认小样式。查看源码发现TwoRowsTopAppBar中单独定义了两者的TextStyle,但相关方法为私有,请问如何单独修改这两个标题的样式?
解决方案
问题根源
直接给MediumTopAppBar的title参数传入固定样式的Text组件,会覆盖组件内部根据滚动状态自动切换标题样式的逻辑,导致展开(大标题)和折叠(小标题)阶段都使用同一种样式。
方法一:基于滚动状态动态切换样式
利用scrollBehavior.state.collapsedFraction判断标题折叠状态,为大、小标题分别应用不同样式:
MediumTopAppBar( title = { val scrollState = scrollBehavior.state // collapsedFraction=0为完全展开的大标题,=1为完全折叠的小标题 val textStyle = if (scrollState.collapsedFraction < 0.5f) { // 自定义大标题样式 MaterialTheme.typography.headlineLarge.copy(color = Color.Black) } else { // 默认小标题样式 MaterialTheme.typography.titleLarge.copy(color = MaterialTheme.colorScheme.onSurface) } Text(text = "pageTitle", style = textStyle) }, navigationIcon = { IconButton(onClick = { onBackPressed.invoke() }) { Icon( imageVector = Icons.Filled.ArrowBack, contentDescription = stringResource(id = R.string.action_back) ) } }, scrollBehavior = scrollBehavior )
方法二:局部覆盖主题大标题样式
如果需要当前页面的MediumTopAppBar统一使用自定义大标题样式,可通过CompositionLocalProvider局部修改主题Typography,不影响全局:
CompositionLocalProvider( LocalTypography provides MaterialTheme.typography.copy( headlineLarge = MaterialTheme.typography.headlineLarge.copy(color = Color.Black) ) ) { MediumTopAppBar( title = { Text(text = "pageTitle") }, navigationIcon = { IconButton(onClick = { onBackPressed.invoke() }) { Icon( imageVector = Icons.Filled.ArrowBack, contentDescription = stringResource(id = R.string.action_back) ) } }, scrollBehavior = scrollBehavior ) }
默认MediumTopAppBar展开时使用headlineLarge样式,折叠时使用titleLarge样式,仅修改headlineLarge即可单独调整大标题样式。
方法三:自定义标题布局(精细控制)
若需要更灵活的动画和样式控制,可手动实现大、小标题的切换逻辑:
MediumTopAppBar( title = { val scrollState = scrollBehavior.state // 动画参数:控制缩放和透明度 val scale by animateFloatAsState( targetValue = if (scrollState.collapsedFraction > 0.5f) 0.75f else 1f, animationSpec = tween(200) ) val alpha by animateFloatAsState( targetValue = if (scrollState.collapsedFraction > 0.5f) 1f else 0f, animationSpec = tween(200) ) // 大标题(自定义样式) Text( text = "pageTitle", style = MaterialTheme.typography.headlineLarge.copy(color = Color.Black), modifier = Modifier.alpha(1f - alpha) ) // 小标题(默认样式) Text( text = "pageTitle", style = MaterialTheme.typography.titleLarge, modifier = Modifier .alpha(alpha) .scale(scale) .align(Alignment.CenterStart) .offset(y = (-16).dp * (1f - scale)) ) }, navigationIcon = { IconButton(onClick = { onBackPressed.invoke() }) { Icon( imageVector = Icons.Filled.ArrowBack, contentDescription = stringResource(id = R.string.action_back) ) } }, scrollBehavior = scrollBehavior )
内容的提问来源于stack exchange,提问作者Meyben
相关产品推荐
相关产品推荐

