这一节主要了解一下Compose中的SelectionContainer,SelectionContainer是Jetpack Compose中用于启用内容文本选择功能的容器组件,它的核心作用是让其子组件中的文本支持长按选中、复制、粘贴、剪切等系统默认的文本操作,简单总结如下:
场景:
1 长文本阅读与编辑,在文章阅读、消息列表等场景中,用户可能需要复制部分内容。
2 表单或输入界面,当用户需要从预填充的文本中复制部分内容时,SelectionContainer可提升操作便捷性。
3 层级数据选择,在树形结构或列表中,若父节点需反映子节点的部分选中状态,可结合TriStateCheckbox和SelectionContainer实现更复杂的交互。
栗子:
Kotlin
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.text.selection.SelectionContainer
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text
import androidx.compose.material3.TopAppBar
import androidx.compose.material3.TopAppBarDefaults
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun SelectionContainerDemo() {
Scaffold(
topBar = {
TopAppBar(
title = { Text("SelectionContainerDemo") },
colors = TopAppBarDefaults.topAppBarColors(
containerColor = MaterialTheme.colorScheme.primaryContainer
)
)
}
) { padding ->
Column(
modifier = Modifier
.fillMaxSize()
.padding(padding)
.padding(16.dp)
) {
Text(
text = "我是普通文本,长按无法选中",
style = MaterialTheme.typography.bodyLarge
)
Spacer(modifier = Modifier.height(20.dp))
SelectionContainer {
Text(
text = "我是可选中的文本,长按试试?\n支持换行文本的选中哦~",
style = MaterialTheme.typography.bodyLarge
)
}
Spacer(modifier = Modifier.height(20.dp))
SelectionContainer {
Column {
Text(
text = "这是第一段可选中的文本",
style = MaterialTheme.typography.bodyLarge
)
Text(
text = "这是第二段可选中的文本,能和上段文本一起被选中",
style = MaterialTheme.typography.bodyLarge
)
}
}
}
}
}
Kotlin
import androidx.compose.foundation.BorderStroke
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.text.selection.DisableSelection
import androidx.compose.foundation.text.selection.SelectionContainer
import androidx.compose.material.Divider
import androidx.compose.material3.Card
import androidx.compose.material3.CardDefaults
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
data class Article(
val title: String,
val author: String,
val publishTime: String,
val content: List<String>,
val quote: String,
val codeBlock: String
)
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun SelectionContainerDemo2() {
val article = remember {
Article(
title = "Compose中SelectionContainer的Demo",
author = "Compose笔记",
publishTime = "2025-12-14",
content = listOf(
"SelectionContainer是Jetpack Compose中用于启用文本选择功能的核心容器组件,它可以让子组件中的文本支持长按选中、复制、粘贴等系统默认操作。",
"与普通Text组件不同,默认情况下Text组件是不支持文本选择的,必须包裹在SelectionContainer中才能启用该功能。"
),
quote = "重点:SelectionContainer支持跨组件选中文本,多个Text组件包裹在同一个SelectionContainer中时,用户可以连续选中所有文本。",
codeBlock = "// 示例代码\nSelectionContainer {\n Text(text = \"可选中的文本\")\n}\n\nDisableSelection {\n Text(text = \"不可选中的文本\")\n}"
)
}
androidx.compose.foundation.lazy.LazyColumn(
modifier = Modifier.fillMaxSize(),
contentPadding = PaddingValues(horizontal = 16.dp, vertical = 20.dp),
verticalArrangement = Arrangement.spacedBy(16.dp)
) {
item {
DisableSelection {
Column(
modifier = Modifier.fillMaxWidth(),
verticalArrangement = Arrangement.spacedBy(8.dp)
) {
Text(
text = article.title,
fontSize = 24.sp,
fontWeight = FontWeight.Bold,
color = MaterialTheme.colorScheme.onBackground
)
Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.SpaceBetween,
verticalAlignment = Alignment.CenterVertically
) {
Text(
text = "作者:${article.author}",
fontSize = 14.sp,
color = MaterialTheme.colorScheme.onBackground.copy(alpha = 0.7f)
)
Text(
text = article.publishTime,
fontSize = 14.sp,
color = MaterialTheme.colorScheme.onBackground.copy(alpha = 0.7f)
)
}
Divider(
color = MaterialTheme.colorScheme.onBackground.copy(alpha = 0.1f),
thickness = 1.dp
)
}
}
}
item {
SelectionContainer {
Column(
modifier = Modifier.fillMaxWidth(),
verticalArrangement = Arrangement.spacedBy(12.dp)
) {
article.content.forEach { paragraph ->
Text(
text = paragraph,
fontSize = 16.sp,
lineHeight = 24.sp,
)
}
}
}
}
item {
SelectionContainer {
Card(
modifier = Modifier.fillMaxWidth(),
shape = RoundedCornerShape(8.dp),
border = BorderStroke(1.dp, MaterialTheme.colorScheme.primary.copy(alpha = 0.3f)),
colors = CardDefaults.cardColors(
containerColor = MaterialTheme.colorScheme.primary.copy(alpha = 0.05f)
)
) {
Text(
text = article.quote,
modifier = Modifier.padding(16.dp),
fontSize = 16.sp,
lineHeight = 24.sp,
color = MaterialTheme.colorScheme.primary
)
}
}
}
item {
DisableSelection {
Card(
modifier = Modifier.fillMaxWidth(),
shape = RoundedCornerShape(8.dp),
colors = CardDefaults.cardColors(
containerColor = Color(0xFFF5F5F5)
)
) {
Text(
text = article.codeBlock,
modifier = Modifier.padding(16.dp),
fontSize = 14.sp,
lineHeight = 20.sp,
color = Color(0xFF333333)
)
}
}
}
}
}
注意:
1 避免在SelectionContainer中包裹大量文本或复杂布局,未渲染的文本项不会被包含在选择操作中,且可能影响性能。
2 与DisableSelection配合 若需禁止部分文本的选择,用DisableSelection包裹目标组件。
3 懒加载布局的兼容性 在LazyColumn或LazyRow中使用SelectionContainer时,仅当前可见的文本项可被选择,滑动后新渲染的项需重新触发选择操作。