这一节主要了解一下Compose中的文本折叠,在Compose应用开发中,经常会用文本折叠的UI场景,现简单总结:
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.material.Icon
import androidx.compose.material.Text
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.KeyboardArrowDown
import androidx.compose.material.icons.filled.KeyboardArrowUp
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
/**
* 可展开/收起的文本控件
* @param text 要显示的文本内容
* @param collapsedMaxLines 折叠状态下最大显示行数
* @param moreText "更多"文本
* @param lessText "收起"文本
* @param textColor 文本颜色
* @param actionTextColor 操作文本("更多"/"收起")颜色
*/
@Composable
fun TestExpandableText(
text: String,
modifier: Modifier = Modifier,
collapsedMaxLines: Int = 2,
moreText: String = "更多",
lessText: String = "收起",
textColor: Color = Color.Black,
actionTextColor: Color = Color.Blue
) {
var expanded by remember { mutableStateOf(false) }
var hasVisualOverflow by remember { mutableStateOf(false) }
Column(modifier = modifier) {
Text(
text = text,
color = textColor,
fontSize = 16.sp,
maxLines = if (expanded) Int.MAX_VALUE else collapsedMaxLines,
overflow = TextOverflow.Ellipsis,
modifier = Modifier.fillMaxWidth(),
onTextLayout = { textLayoutResult ->
hasVisualOverflow = textLayoutResult.hasVisualOverflow
}
)
if (hasVisualOverflow) {
Row(
modifier = Modifier
.fillMaxWidth()
.padding(top = 8.dp),
horizontalArrangement = Arrangement.Center,
verticalAlignment = Alignment.CenterVertically
) {
Text(
text = if (expanded) lessText else moreText,
color = actionTextColor,
fontSize = 14.sp,
modifier = Modifier
.clickable { expanded = !expanded }
.padding(end = 4.dp)
)
Icon(
imageVector = if (expanded) Icons.Filled.KeyboardArrowUp else Icons.Filled.KeyboardArrowDown,
contentDescription = if (expanded) "收起" else "更多",
tint = actionTextColor,
modifier = Modifier.clickable { expanded = !expanded }
)
}
}
}
}
// 预览
@Composable
fun ExpandableTextPreview() {
val longText = "这是一段较长的文本内容,用于测试可展开收起功能。当文本内容超过两行时," +
"会自动显示省略号,并在底部显示'更多'按钮。点击'更多'后,会展示全部文本内容," +
"同时按钮变为'收起'。再次点击则会折叠回两行显示状态。"
Column(
modifier = Modifier
.padding(16.dp)
.fillMaxWidth()
) {
Text("短文本示例:", fontSize = 16.sp, fontWeight = androidx.compose.ui.text.font.FontWeight.Bold)
TestExpandableText(
text = "这是一段短文本,不会超过两行显示。",
modifier = Modifier.padding(vertical = 8.dp)
)
Text("长文本示例:", fontSize = 16.sp, fontWeight = androidx.compose.ui.text.font.FontWeight.Bold)
TestExpandableText(
text = longText,
modifier = Modifier.padding(vertical = 8.dp)
)
}
}
滑动列表自动折叠文本
mport androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.rememberLazyListState
import androidx.compose.runtime.*
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.compose.foundation.layout.*
import androidx.compose.material.Icon
import androidx.compose.material.Text
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.KeyboardArrowDown
import androidx.compose.material.icons.filled.KeyboardArrowUp
import androidx.compose.ui.Alignment
import androidx.compose.ui.text.style.TextOverflow
@Composable
fun TestExpandableText(
text: String,
expanded: Boolean,
onExpandedChange: (Boolean) -> Unit,
modifier: Modifier = Modifier,
collapsedMaxLines: Int = 2,
moreText: String = "更多",
lessText: String = "收起",
textColor: Color = Color.Black,
actionTextColor: Color = Color.Blue
) {
var hasOverflow by remember { mutableStateOf(false) }
Column(modifier = modifier) {
Text(
text = text,
color = textColor,
fontSize = 16.sp,
maxLines = if (expanded) Int.MAX_VALUE else collapsedMaxLines,
overflow = TextOverflow.Ellipsis,
modifier = Modifier.fillMaxWidth(),
onTextLayout = { textLayoutResult ->
if (!expanded) {
hasOverflow = textLayoutResult.hasVisualOverflow
}
}
)
if (hasOverflow) {
Row(
modifier = Modifier
.fillMaxWidth()
.padding(top = 8.dp),
horizontalArrangement = Arrangement.Center,
verticalAlignment = Alignment.CenterVertically
) {
Text(
text = if (expanded) lessText else moreText,
color = actionTextColor,
fontSize = 14.sp,
modifier = Modifier
.clickable { onExpandedChange(!expanded) }
.padding(end = 4.dp)
)
Icon(
imageVector = if (expanded) Icons.Filled.KeyboardArrowUp else Icons.Filled.KeyboardArrowDown,
contentDescription = if (expanded) "收起" else "更多",
tint = actionTextColor,
modifier = Modifier.clickable { onExpandedChange(!expanded) }
)
}
}
}
}
@Composable
fun ScrollAwareExpandableScreen() {
// 文本内容
val longText = "这是一段较长的文本内容,用于测试可展开收起功能。当文本内容超过两行时," +
"会自动显示省略号,并在底部显示'更多'按钮。点击'更多'后,会展示全部文本内容," +
"同时按钮变为'收起'并且仍然可见。当您滑动下方的列表时,展开的文本会自动折叠。" +
"再次点击则会折叠回两行显示状态。这是一段较长的文本内容,用于测试可展开收起功能。"
var textExpanded by remember { mutableStateOf(false) }
val listState = rememberLazyListState()
LaunchedEffect(listState.isScrollInProgress) {
if (listState.isScrollInProgress && textExpanded) {
textExpanded = false
}
}
Column(
modifier = Modifier
.fillMaxSize()
.padding(16.dp)
) {
// 上部:可展开文本
TestExpandableText(
text = longText,
expanded = textExpanded,
onExpandedChange = { textExpanded = it },
modifier = Modifier.padding(bottom = 16.dp)
)
// 下部:列表
Text(
text = "列表内容:",
fontSize = 16.sp,
fontWeight = androidx.compose.ui.text.font.FontWeight.Bold,
modifier = Modifier.padding(bottom = 8.dp)
)
LazyColumn(
state = listState,
modifier = Modifier.fillMaxSize()
) {
items(50) { index ->
Box(
modifier = Modifier
.fillMaxWidth()
.height(60.dp)
.padding(vertical = 4.dp)
.background(Color.LightGray.copy(alpha = 0.3f)),
contentAlignment = Alignment.Center
) {
Text(text = "列表项 ${index + 1}")
}
}
}
}
}
// 预览
@Composable
fun TestScrollAwareExpandableScreenPreview() {
ScrollAwareExpandableScreen()
}