Compose Text 高级用法:富文本、样式与交互

2024-05-18 · 24 min · 文本处理

Text 是 UI 中最基础也最重要的组件。Compose 提供了强大的文本处理能力,从简单的文字显示到复杂的富文本、可点击文本、文本选择等。

一、Text 基础

Text(
    text = "Hello, Compose!",
    color = Color.Blue,
    fontSize = 20.sp,
    fontWeight = FontWeight.Bold,
    maxLines = 2,
    overflow = TextOverflow.Ellipsis
)

二、AnnotatedString 富文本

@Composable
fun RichText() {
    val annotatedString = buildAnnotatedString {
        append("这是")
        
        withStyle(SpanStyle(color = Color.Red, fontWeight = FontWeight.Bold)) {
            append("红色粗体")
        }
        
        append("文字。")
    }
    
    Text(text = annotatedString)
}

三、可点击文本

val annotatedString = buildAnnotatedString {
    append("请阅读")
    
    pushStringAnnotation(tag = "URL", annotation = "https://example.com")
    withStyle(SpanStyle(color = Color.Blue, textDecoration = TextDecoration.Underline)) {
        append("服务条款")
    }
    pop()
}

ClickableText(
    text = annotatedString,
    onClick = { offset ->
        annotatedString.getStringAnnotations("URL", offset, offset)
            .firstOrNull()?.let { println(it.item) }
    }
)

四、文本选择

SelectionContainer {
    Column {
        Text("可选择的文字")
        
        DisableSelection {
            Text("不可选择的文字")
        }
    }
}

五、TextField 高级用法

@Composable
fun PasswordTextField() {
    var password by remember { mutableStateOf("") }
    var visible by remember { mutableStateOf(false) }
    
    OutlinedTextField(
        value = password,
        onValueChange = { password = it },
        label = { Text("密码") },
        visualTransformation = if (visible) 
            VisualTransformation.None 
        else 
            PasswordVisualTransformation(),
        trailingIcon = {
            IconButton(onClick = { visible = !visible }) {
                Icon(
                    if (visible) Icons.Default.Visibility else Icons.Default.VisibilityOff,
                    contentDescription = null
                )
            }
        }
    )
}

六、文本动画

@Composable
fun AnimatedCounter(count: Int) {
    val animatedCount by animateIntAsState(
        targetValue = count,
        animationSpec = tween(1000),
        label = "counter"
    )
    
    Text(
        text = animatedCount.toString(),
        style = MaterialTheme.typography.displayLarge
    )
}

总结