登录
推荐 文章 Go 技术 课程 下载 专题 AI
首页 >  文章 >  软件教程

compose 实现AutoSizeText

时间:2026-08-20 23:10:31 271浏览 收藏

使用二分查找法实现Text的字体大小自适应,代码如下:

compose 实现AutoSizeText

import androidx.compose.foundation.layout.BoxWithConstraints
import androidx.compose.material3.LocalTextStyle
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.text.AnnotatedString
import androidx.compose.ui.text.TextLayoutResult
import androidx.compose.ui.text.TextMeasurer
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.font.FontFamily
import androidx.compose.ui.text.font.FontStyle
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.rememberTextMeasurer
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.text.style.TextDecoration
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.Constraints
import androidx.compose.ui.unit.TextUnit
import androidx.compose.ui.unit.sp

@Composable
fun AutoSizeText(
    text: String,
    modifier: Modifier = Modifier,
    color: Color = Color.Unspecified,
    fontStyle: FontStyle? = null,
    fontWeight: FontWeight? = null,
    fontFamily: FontFamily? = null,
    letterSpacing: TextUnit = TextUnit.Unspecified,
    textDecoration: TextDecoration? = null,
    textAlign: TextAlign = TextAlign.Unspecified,
    lineHeight: TextUnit = TextUnit.Unspecified,
    maxLines: Int = 1,
    overflow: TextOverflow = TextOverflow.Ellipsis,
    onTextLayout: ((TextLayoutResult) -> Unit)? = null,
    style: TextStyle = LocalTextStyle.current.copy(
        color = color,
        fontStyle = fontStyle,
        fontWeight = fontWeight,
        fontFamily = fontFamily,
        letterSpacing = letterSpacing,
        textDecoration = textDecoration,
        textAlign = textAlign,
        lineHeight = lineHeight,
    ),
    maxFontSize: TextUnit = 100.sp,
    minFontSize: TextUnit = 10.sp,
) {
    val textMeasurer = rememberTextMeasurer()

    BoxWithConstraints(modifier = modifier) {
        // 1. 获取容器的约束尺寸
        val maxWidthPx = constraints.maxWidth
        val maxHeightPx = constraints.maxHeight

        // 2. 使用 remember 缓存计算结果,只有 text 或约束改变时才重新计算
        val optimizedFontSize = remember(text, maxWidthPx, maxHeightPx) {
            var low = minFontSize.value
            var high = maxFontSize.value
            var res = low

            // 二分查找循环
            while (low val mid = (low + high) / 2
                val isFit = checkTextFit(
                    textMeasurer = textMeasurer,
                    text = text,
                    fontSize = mid.sp,
                    style = style,
                    maxWidthPx = maxWidthPx,
                    maxHeightPx = maxHeightPx,
                    maxLines = maxLines
                )
                if (isFit) {
                    res = mid
                    low = mid + 0.5f // 尝试更大的字号(步长可调)
                } else {
                    high = mid - 0.5f // 字号太大了,调小一点
                }
            }
            res.sp
        }

        // 3. 最终渲染
        Text(
            text = text,
            color = color,
            fontSize = optimizedFontSize,
            style = style,
            maxLines = maxLines,
            overflow = overflow,
            onTextLayout = onTextLayout
        )
    }
}

/**
 * 核心辅助函数:使用 TextMeasurer 在内存中测量文字是否溢出
 */
private fun checkTextFit(
    textMeasurer: TextMeasurer,
    text: String,
    fontSize: TextUnit,
    style: TextStyle,
    maxWidthPx: Int,
    maxHeightPx: Int,
    maxLines: Int
): Boolean {
    val layoutResult = textMeasurer.measure(
        text = AnnotatedString(text),
        style = style.copy(fontSize = fontSize),
        maxLines = maxLines,
        constraints = Constraints(maxWidth = maxWidthPx, maxHeight = maxHeightPx)
    )
    // 同时检查宽度和高度是否在容器范围内
    return layoutResult.size.width 

以上是完整代码,可直接使用。

简单分析

通过checkTextFit方法来判断文字是否超出容器范围。要是超出了,就执行high = mid - 0.5f,这意味着要把字号调小一点;要是没超出呢,就执行low = mid + 0.5f,这是在尝试更大的字号(步长是可以调整的哦)。就这样一直循环,直到low > high,当不满足这个循环条件的时候,得到的res就是自适应的字体大小啦。

相关阅读
更多>
最新阅读
更多>
课程推荐
更多>