Wear OS Compose中Chip适配系统字体大小的实现问题
Wear OS Jetpack Compose Chip 适配系统字体大小问题修复
问题现象
使用Jetpack Compose开发Wear OS应用时,Chip组件在系统字体设为默认时显示正常,但调至最大字号时,Chip内的文字会溢出底部,无法自适应调整组件高度。
原代码
fun MainScreen( userPreferences: SharedPreferences, oneTrainingsOnClick: () -> Unit, freeTrainingOnClick: () -> Unit, settingsOnClick: () -> Unit, signInOnClick: () -> Unit ) { val isUserLoggedIn = userPreferences.getBoolean(MainActivity.LOG_IN, false) val chipColor = colorResource(id = R.color.gray) val listState = rememberScalingLazyListState(initialCenterItemIndex = 0) val coroutineScope = rememberCoroutineScope() val focusRequester = remember { FocusRequester() } Scaffold( positionIndicator = { PositionIndicator(scalingLazyListState = listState) }, timeText = { TimeOnList(listState) }, vignette = { Vignette(vignettePosition = VignettePosition.TopAndBottom) } ) { ScalingLazyColumn( state = listState, modifier = Modifier .fillMaxSize() .onRotaryScrollEvent { coroutineScope.launch { listState.scrollBy(it.verticalScrollPixels) } true } .focusRequester(focusRequester) .focusable() ) { item { Chip( icon = { Image( painter = painterResource(id = R.drawable.ic_one_icon), contentDescription = null ) }, onClick = { if (isUserLoggedIn) oneTrainingsOnClick() else signInOnClick() }, enabled = true, colors = ChipDefaults.chipColors(chipColor), modifier = Modifier .wrapContentSize() .fillMaxWidth() .padding(top = 40.dp), shape = RoundedCornerShape(30.dp), label = { Text( text = if (isUserLoggedIn) stringResource(id = R.string.one_trainings_button) else stringResource(id = R.string.start), style = TextStyle( textAlign = TextAlign.Left, fontFamily = Font(R.font.roboto_bold).toFontFamily(), fontSize = dimensionResource(id = R.dimen.general_text).value.sp, color = colorResource(id = R.color.white) ), maxLines = 2, modifier = Modifier.fillMaxWidth() ) }, ) } item { Chip( icon = { Image( painter = painterResource(id = R.drawable.ic_free_training), contentDescription = null ) }, onClick = { freeTrainingOnClick() }, colors = ChipDefaults.chipColors(chipColor), modifier = Modifier.fillMaxWidth(), shape = RoundedCornerShape(30.dp), label = { Text( text = stringResource(id = R.string.free_training_button), style = TextStyle( textAlign = TextAlign.Left, fontFamily = Font(R.font.roboto_bold).toFontFamily(), fontSize = dimensionResource(id = R.dimen.general_text).value.sp, color = colorResource(id = R.color.white) ), // overflow = TextOverflow.Ellipsis, // maxLines = 1, modifier = Modifier.fillMaxWidth() ) } ) } item { Chip( icon = { Image( painter = painterResource(id = R.drawable.ic_settings), contentDescription = null ) }, onClick = { settingsOnClick() }, colors = ChipDefaults.chipColors(chipColor), modifier = Modifier.fillMaxWidth(), shape = RoundedCornerShape(30.dp), label = { Text( text = stringResource(id = R.string.configuration_text), maxLines = 1, style = TextStyle( textAlign = TextAlign.Left, fontFamily = Font(R.font.roboto_bold).toFontFamily(), fontSize = dimensionResource(id = R.dimen.general_text).value.sp, color = colorResource(id = R.color.white) ), overflow = TextOverflow.Ellipsis, modifier = Modifier.fillMaxWidth() ) }, secondaryLabel = { Text(text = stringResource(id = R.string.failed_authentication)) } ) } } LaunchedEffect(Unit) { focusRequester.requestFocus() } } }
修复方案
- 正确适配系统字体缩放:原代码中通过
dimensionResource(id = R.dimen.general_text).value.sp设置字号的方式错误,会丢失系统字体缩放比例。直接使用dimensionResource作为fontSize值(确保general_text在dimens.xml中定义为sp单位),系统会自动应用字体缩放。 - 让Chip自适应高度:移除Chip上不必要的
wrapContentSize()修饰符,保留fillMaxWidth()让组件占满宽度,同时允许高度根据内容自动调整。 - 合理设置文本换行规则:根据文本长度设置合适的
maxLines,避免强制单行导致溢出;对于不需要换行的文本,保留TextOverflow.Ellipsis防止溢出。
修改后的代码
fun MainScreen( userPreferences: SharedPreferences, oneTrainingsOnClick: () -> Unit, freeTrainingOnClick: () -> Unit, settingsOnClick: () -> Unit, signInOnClick: () -> Unit ) { val isUserLoggedIn = userPreferences.getBoolean(MainActivity.LOG_IN, false) val chipColor = colorResource(id = R.color.gray) val listState = rememberScalingLazyListState(initialCenterItemIndex = 0) val coroutineScope = rememberCoroutineScope() val focusRequester = remember { FocusRequester() } // 复用文本样式,避免重复代码 val chipTextStyle = TextStyle( textAlign = TextAlign.Left, fontFamily = Font(R.font.roboto_bold).toFontFamily(), fontSize = dimensionResource(id = R.dimen.general_text), // 直接使用dimensionResource适配缩放 color = colorResource(id = R.color.white) ) Scaffold( positionIndicator = { PositionIndicator(scalingLazyListState = listState) }, timeText = { TimeOnList(listState) }, vignette = { Vignette(vignettePosition = VignettePosition.TopAndBottom) } ) { ScalingLazyColumn( state = listState, modifier = Modifier .fillMaxSize() .onRotaryScrollEvent { coroutineScope.launch { listState.scrollBy(it.verticalScrollPixels) } true } .focusRequester(focusRequester) .focusable() ) { item { Chip( icon = { Image( painter = painterResource(id = R.drawable.ic_one_icon), contentDescription = null ) }, onClick = { if (isUserLoggedIn) oneTrainingsOnClick() else signInOnClick() }, enabled = true, colors = ChipDefaults.chipColors(chipColor), modifier = Modifier .fillMaxWidth() .padding(top = 40.dp), // 移除不必要的wrapContentSize shape = RoundedCornerShape(30.dp), label = { Text( text = if (isUserLoggedIn) stringResource(id = R.string.one_trainings_button) else stringResource(id = R.string.start), style = chipTextStyle, maxLines = 2, // 允许两行换行,避免溢出 modifier = Modifier.fillMaxWidth() ) }, ) } item { Chip( icon = { Image( painter = painterResource(id = R.drawable.ic_free_training), contentDescription = null ) }, onClick = { freeTrainingOnClick() }, colors = ChipDefaults.chipColors(chipColor), modifier = Modifier.fillMaxWidth(), shape = RoundedCornerShape(30.dp), label = { Text( text = stringResource(id = R.string.free_training_button), style = chipTextStyle, maxLines = 2, // 允许换行 modifier = Modifier.fillMaxWidth() ) } ) } item { Chip( icon = { Image( painter = painterResource(id = R.drawable.ic_settings), contentDescription = null ) }, onClick = { settingsOnClick() }, colors = ChipDefaults.chipColors(chipColor), modifier = Modifier.fillMaxWidth(), shape = RoundedCornerShape(30.dp), label = { Text( text = stringResource(id = R.string.configuration_text), style = chipTextStyle, maxLines = 1, overflow = TextOverflow.Ellipsis, // 单行时用省略号防止溢出 modifier = Modifier.fillMaxWidth() ) }, secondaryLabel = { Text( text = stringResource(id = R.string.failed_authentication), style = chipTextStyle.copy(fontSize = dimensionResource(id = R.dimen.smaller_text)) // 次级文本字号可单独设置 ) } ) } } LaunchedEffect(Unit) { focusRequester.requestFocus() } } }
额外注意事项
- 确认
res/values/dimens.xml中general_text的定义为sp单位,例如:<dimen name="general_text">16sp</dimen>,这样系统字体缩放时会同步调整字号。 - Wear OS的Chip组件默认已经支持自适应内容高度,只要不强制固定高度,就能随文本大小变化自动调整。
内容的提问来源于stack exchange,提问作者Santiago Melo
相关产品推荐
相关产品推荐

