Compose笔记(五十一)--rememberTextMeasurer

这一节主要了解一下Compose中的rememberTextMeasurer,在Jetpack Compose开发中,rememberTextMeasurer是用于测量文本尺寸的工具,它可以帮助我们在不实际绘制文本的情况下,获取文本的宽度、高度、行数等信息。

API

measure(text: AnnotatedString, style: TextStyle, constraints: Constraints):测量文本尺寸,返回TextLayoutResult;

TextLayoutResult:包含文本测量结果,如size(宽高)、lineCount(行数)、getLineEnd()(每行结束索引)等;
场景

文本尺寸预测量:在不渲染文本的情况下获取宽高、行数等信息,为布局决策提供依据

动态布局适配:根据容器大小自动调整文本属性(如字体大小、行数)

交互逻辑支持:实现文本截断、展开 / 收起等依赖文本尺寸的交互功能

栗子:

Kotlin 复制代码
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
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.platform.LocalDensity
import androidx.compose.ui.text.AnnotatedString
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.rememberTextMeasurer
import androidx.compose.ui.unit.Constraints
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp

@Composable
fun TestDemo() {
    val density = LocalDensity.current
    val textMeasurer = rememberTextMeasurer()
    val containerWidth: Dp = 250.dp 
    val targetText = "使用二分法快速找到适合容器的字体大小......"

   
    val suitableFontSize = remember(targetText, containerWidth, density) {
        val containerWidthPx = with(density) { containerWidth.roundToPx() }
        var minSize = 8.sp    
        var maxSize = 30.sp   
        var bestSize = minSize 

    
        repeat(10) {

            val midSize = ((minSize.value + maxSize.value) / 2).sp 
            val textLayoutResult = textMeasurer.measure(
                text = AnnotatedString(targetText),
                style = TextStyle(fontSize = midSize),
                constraints = Constraints(maxWidth = containerWidthPx)
            )

            if (textLayoutResult.size.width <= containerWidthPx) {            
                bestSize = midSize
                minSize = midSize
            } else {    
                maxSize = midSize
            }
        }
        bestSize
    }

    Box(
        modifier = Modifier
            .fillMaxWidth()
            .padding(16.dp)
    ) {
        Text(
            text = targetText,
            style = TextStyle(
                fontSize = suitableFontSize,
                color = Color.Black,
                letterSpacing = 0.5.sp
            ),
            modifier = Modifier.padding(8.dp)
        )
    }
}
Kotlin 复制代码
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.Button
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.text.AnnotatedString
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.Constraints
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.rememberTextMeasurer
import androidx.compose.ui.text.style.LineBreak
import androidx.compose.ui.unit.Dp

@Composable
fun TextExample() {
    val density = LocalDensity.current
    val textMeasurer = rememberTextMeasurer()
    val maxDisplayLines = 2
    val containerWidth: Dp = 300.dp
    val fullText = "这是一段较长的文本内容,用于演示文本展开和收起功能。" +
            "当文本内容超过指定的最大行数时,会显示「展开」按钮;" +
            "点击后查看全部内容,再次点击则「收起」回到指定行数。"

    val textLayoutResult = remember(fullText, containerWidth, density) {
        val containerWidthPx = with(density) { containerWidth.roundToPx() }

        textMeasurer.measure(
            text = AnnotatedString(fullText),
            style = TextStyle(
                fontSize = 16.sp,
                color = Color.Black,
                lineHeight = 24.sp,
                lineBreak = LineBreak.Paragraph,
            ),
            constraints = Constraints(maxWidth = containerWidthPx)
        )
    }

    val needExpandButton = textLayoutResult.lineCount > maxDisplayLines
    var isExpanded by remember { mutableStateOf(false) }

    Box(
        modifier = Modifier
            .fillMaxWidth()
            .padding(16.dp)
    ) {
        Text(
            text = fullText,
            style = TextStyle(
                fontSize = 16.sp,
                color = Color.Black,
                lineHeight = 24.sp
            ),
            maxLines = if (isExpanded) Int.MAX_VALUE else maxDisplayLines,
            overflow = if (needExpandButton && !isExpanded) TextOverflow.Ellipsis else TextOverflow.Visible,
            modifier = Modifier.fillMaxWidth()
        )

        if (needExpandButton) {
            Button(
                onClick = { isExpanded = !isExpanded },
                modifier = Modifier
                    .align(Alignment.BottomEnd)
                    .padding(top = 8.dp)
            ) {
                Text(if (isExpanded) "收起" else "展开")
            }
        }
    }
}

注意

1.避免重复创建TextMeasurer;

2.性能优化:在滚动列表或动画中频繁调用measure()可能导致卡顿,避免频繁测量;

3.TextMeasurer仅测量文本布局,不处理实际渲染或交互;

相关推荐
半壶清水几秒前
[软考网规考点笔记]-软件开发、项目管理与知识产权核心知识与真题解析
网络·笔记·压力测试
JMchen12319 分钟前
Android后台服务与网络保活:WorkManager的实战应用
android·java·网络·kotlin·php·android-studio
tq108625 分钟前
先探索,后设计
笔记
hnult31 分钟前
2026 在线培训考试系统选型指南:核心功能拆解与选型逻辑
人工智能·笔记·课程设计
AI视觉网奇43 分钟前
ue 角色驱动衣服 绑定衣服
笔记·学习·ue5
crmscs1 小时前
剪映永久解锁版/电脑版永久会员VIP/安卓SVIP手机永久版下载
android·智能手机·电脑
localbob1 小时前
杀戮尖塔 v6 MOD整合版(Slay the Spire)安卓+PC端免安装中文版分享 卡牌肉鸽神作!杀戮尖塔中文版,电脑和手机都能玩!杀戮尖塔.exe 杀戮尖塔.apk
android·杀戮尖塔apk·杀戮尖塔exe·游戏分享
机建狂魔1 小时前
手机秒变电影机:Blackmagic Camera + LUT滤镜包的专业级视频解决方案
android·拍照·摄影·lut滤镜·拍摄·摄像·录像
hudawei9961 小时前
flutter和Android动画的对比
android·flutter·动画
三水不滴1 小时前
计网ping原理
经验分享·笔记·计算机网络