这一节主要了解一下Compose中的SegmentedButton,在Jetpack Compose中,SegmentedButton是一种用于在多个互斥选项间快速切换的UI组件,通常呈现为一组水平排列的按钮,用户只能选中其中一个,或者非互斥选项间,用户可选其中多个,简单总结如下:
场景:
1 选项筛选,在列表或表格中切换筛选条件
2 视图切换,在同一个页面中切换不同的视图模式
3 表单中的单选输入,在表单中选择性别、支付方式等单选字段
栗子:
Kotlin
import androidx.compose.material3.SegmentedButton
import androidx.compose.material3.SegmentedButtonDefaults
import androidx.compose.material3.SingleChoiceSegmentedButtonRow
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableIntStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
@Composable
fun SegmentedButtonDemo() {
var selectedIndex by remember { mutableIntStateOf(0) }
val options = listOf("日", "周", "月")
SingleChoiceSegmentedButtonRow {
options.forEachIndexed { index, label ->
SegmentedButton(
shape = SegmentedButtonDefaults.itemShape(index, options.size),
onClick = { selectedIndex = index },
selected = index == selectedIndex,
label = { Text(label) }
)
}
}
}
Kotlin
import androidx.compose.foundation.layout.*
import androidx.compose.material3.*
import androidx.compose.runtime.*
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
@Composable
fun SegmentedButtonDemo() {
val hobbyTags = listOf("篮球", "音乐", "阅读", "游戏", "摄影")
val checkedStates = remember {
mutableStateOf(
hobbyTags.associateWith { false }.toMutableMap()
)
}
val selectedHobbies = remember { mutableStateOf(setOf<String>()) }
MultiChoiceSegmentedButtonRow(
modifier = Modifier.padding(16.dp),
space = SegmentedButtonDefaults.BorderWidth
) {
hobbyTags.forEachIndexed { index, tag ->
val shape = SegmentedButtonDefaults.itemShape(
index = index,
count = hobbyTags.size,
baseShape = MaterialTheme.shapes.small
)
SegmentedButton(
checked = selectedHobbies.value.contains(tag),
onCheckedChange = { isChecked ->
selectedHobbies.value = if (isChecked) {
selectedHobbies.value + tag
} else {
selectedHobbies.value - tag
}
},
shape = shape,
modifier = Modifier,
enabled = true,
colors = SegmentedButtonDefaults.colors(),
border = SegmentedButtonDefaults.borderStroke(
color = MaterialTheme.colorScheme.outline
),
label = { Text(tag) }
)
}
}
Text(
modifier = Modifier.padding(start = 16.dp, top = 8.dp),
text = "当前选中爱好:${
if (selectedHobbies.value.isEmpty()) "无" else selectedHobbies.value.joinToString(", ")
}",
style = MaterialTheme.typography.bodyMedium
)
}
Kotlin
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.MultiChoiceSegmentedButtonRow
import androidx.compose.material3.SegmentedButton
import androidx.compose.material3.SegmentedButtonDefaults
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import androidx.lifecycle.viewmodel.compose.viewModel
@Composable
fun SegmentedButtonDemo(
viewModel: LanguageSelectViewModel = viewModel()
) {
val languageOptions = listOf(
LanguageOption("zh-CN", "中文"),
LanguageOption("en-US", "英文"),
LanguageOption("ja-JP", "日语"),
LanguageOption("ko-KR", "韩语")
)
val selectedLanguages = viewModel.selectedLanguages.collectAsStateWithLifecycle(initialValue = emptySet())
MultiChoiceSegmentedButtonRow(
modifier = Modifier.padding(horizontal = 0.dp),
space = SegmentedButtonDefaults.BorderWidth
) {
languageOptions.forEachIndexed { index, option ->
val shape = SegmentedButtonDefaults.itemShape(
index = index,
count = languageOptions.size,
baseShape = MaterialTheme.shapes.small
)
SegmentedButton(
checked = selectedLanguages.value.contains(option.code),
onCheckedChange = { isChecked ->
viewModel.updateLanguageSelection(option.code, isChecked)
},
shape = shape,
colors = SegmentedButtonDefaults.colors(
),
label = { Text(option.name) }
)
}
}
}
Kotlin
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.launch
data class LanguageOption(
val code: String,
val name: String
)
class LanguageSelectViewModel : ViewModel() {
private val _selectedLanguages = MutableStateFlow(setOf<String>())
val selectedLanguages: StateFlow<Set<String>> = _selectedLanguages.asStateFlow()
fun updateLanguageSelection(code: String, isChecked: Boolean) {
viewModelScope.launch {
_selectedLanguages.value = if (isChecked) {
_selectedLanguages.value + code
} else {
_selectedLanguages.value - code
}
}
}
}
注意:
1 选项数量限制,选项数量尽量控制在2-5个,过多会导致按钮过小,难以点击。
2 选项文本长度,选项文本尽量简短,避免换行。