文章

Jetpack Compose:文本组件

一、Text

Text 遵循 Material Design 设计规范,如无需使用 Material Design 可以使用更底层的 BasicText 组件。

Text 函数如下所示:

@Composable
fun Text(
	text: String,									// 显示的文本
    modifier: Modifier = Modifier,					// 修饰符
    color: Color = Color.Unspecified,				// 文本颜色
    fontSize: TextUnit = TextUnit.Unspecified,		// 文字大小
    fontStyle: FontStyle ?= null,					// 字体样式
    fontWeight: FontWeight ?= null,					// 文本粗细
    fontFamily: FontFamily ?= null,					// 文本字体
    letterSpacing: TextUnit = TextUnit.Unspecified,	// 文本间距
    textDecoration: TextDecoration ?= null,			// 文本装饰
    textAlign: TextAlign ?= null,					// 文本对齐方式
    lineHeight: TextUnit = TextUnit.Unspecified,	// 文本行高
    overflow: TextOverflow = TextOverflow.Clip,		// 文本溢出效果
    softWrap: Boolean = true,						// 文本是否能换行
    maxLines: Int = Int.MAX_VALUE,					// 文本最多几行
    onTextLayout: (TextLayoutResult) -> Unit = {},	// 文本变化回调
    style: TextStyle = LocalTextStyle.current		// 文本样式
)

Text 一般使用方法如下:

Text(text = "Hello World")
Text(text = stringResource(R.string.hello))

二、AnnotatedString

AnnotatedString 可以在一段文字中突出显示指定文本,例如突出显示网址、电话、邮箱等。

  • buildAnnotatedString 用于构建 AnnotatedString
  • withStyle 用于指定文本样式
  • SpanStyle 用于描述文本样式
  • ParagraphStyle 用于描述段落样式
  • append 用于添加文本
Text(
    
	text = buildAnnotatedString {
		withStyle(style = SpanStyle(fontSize = 20.sp)) {
			append("你好,世界")
		}
        append("\n")
        
        withStyle(style = ParagraphStyle(lineHeight = 24.sp)) {
        	append("你好,这里展示的是 AnnotatedString")
        }
        append("\n")
        
        withStyle(style = SpanStyle(
			fontWeight = FontWeight.Bold,
			textDecoration = TextDecoration.Underline,
			color = Color.Blue
		)) {
			append("我不是罗大锤")
		}
	}
)

SpanStyle 与 ParagraphStyle 的样式设置优先级高于 TextStyle

textComponent_2

三、ClickedText

ClickedText 是一种可以点击的文本组件,可以响应用户对文本的点击并返回点击的位置。

可以组合 AnnotatedString 在点击后响应不同的事件。

修改上一小节 AnnotatedString 代码:

val annotatedText = buildAnnotatedString {
	...
    // 在文本 “我不是罗大锤” 前后添加标签
    pushStringAnnotation(
		tag = "URL",
		annotation = "https://luodachui.cn"
	)
    withStyle(style = SpanStyle(
		fontWeight = FontWeight.Bold,
		textDecoration = TextDecoration.Underline,
		color = Color.Blue
	)) {
 		append("我不是罗大锤")
	}
    // 添加标签
	pop()
}

ClickableText(
	text = annotatedText,
	onClick = { offset ->
        // 获取被点击区域 tag 为 URL 的 annotation
		annotatedText.getStringAnnotations(
			tag = "URL",
			start = offset,
			end = offset
		).firstOrNull()?.let { annotation ->
            // 打开 URL
			openURL(annotation.item)
		}
	}
)

四、SelectionContainer

被 SelectionContainer 包裹的文字可以被复制。

SelectionContainer {
	Text("我是可被复制的")
}

textComponent_3

五、TextField

TextField 遵循 Material Design 设计规范,如无需使用 Material Design 可以使用更底层的 BasicTextField 组件。

TextField 函数如下所示:

@Composable
fun TextField(
    value: TextFieldValue,									// 显示的文本
    onValueChange: (TextFieldValue) -> Unit,				// 文本变化回调
    modifier: Modifier = Modifier,							// 修饰符
    enabled: Boolean = true,								// 是否启用
    readOnly: Boolean = false,								// 是否只读
    textStyle: TextStyle = LocalTextStyle.current,			// 输入框文本样式
    label: @Composable (() -> Unit)? = null,				// 输入框标签
    placeholder: @Composable (() -> Unit)? = null,			// 占位符
    leadingIcon: @Composable (() -> Unit)? = null,			// 输入框开头图标
    trailingIcon: @Composable (() -> Unit)? = null,			// 输入框末尾图标
    isError: Boolean = false,								// 输入框当前内容是否有误(输入框样式变为错误颜色)
    visualTransformation: VisualTransformation = VisualTransformation.None,		// 文本视觉(PasswordVisualTransformation 密码文本)
    keyboardOptions: KeyboardOptions = KeyboardOptions.Default,					// 软键盘选项
    keyboardActions: KeyboardActions = KeyboardActions(),						// 输入服务发出 IME 时,回调被调用
    singleLine: Boolean = false,												// 是否单行
    maxLines: Int = Int.MAX_VALUE,												// 最大行数
    interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },			// 监听组件状态	
    shape: Shape =
        MaterialTheme.shapes.small.copy(bottomEnd = ZeroCornerSize, bottomStart = ZeroCornerSize),	// 输入框外观
    colors: TextFieldColors = TextFieldDefaults.textFieldColors()									// 输入框颜色组
)

TextField 一般使用方法如下:

var name by remember { mutableStateOf("") }
	TextField(
		value = name,
		onValueChange = {
			name = it
		},
		label = {
			Text("姓名")
		}
)

textComponent_4

六、OutlinedTextField

OutlinedTextField 遵循 Material Design 设计规范,相比 TextField 默认带有一个边框。

@Composable
fun init() {
    var text by remember { mutableStateOf("") }
    OutlinedTextField(
    	value = text,
        onValueChange = {
            text = it
        },
        label = {
            Text("姓名")
        }
    )
}

textComponent_1

七、BasicTextField

BasicTextField 是一个低级别的组件,相比 TextField 与 OutlinedTextField 拥有更多的自定义效果。

BasicTextField 关键的一个参数是最后的 decorationBox:

fun BasicTextField(
    ...
    decorationBox: @Composable (innerTextField: @Composable () -> Unit) -> Unit =
        @Composable { innerTextField -> innerTextField() }
)

该参数回调了一个 innerTextField 函数供我们使用,这个函数的作用是定义一个文字的输入入口,当你自定义好了一个输入框界面,需要在相应的地方调用 innerTextField 函数来创建一个输入框。

var text by remember { mutableStateOf("") }
BasicTextField(
	value = text,
	onValueChange = {
		text = it
	},
	decorationBox = { innerTextField ->
		Column(
			modifier = Modifier
				.background(Color.LightGray)
                .height(40.dp)
                .fillMaxWidth()
		) {
			innerTextField()
		}
	},
	textStyle = MaterialTheme.typography.h5
)

textComponent_5

License:  CC BY 4.0