Compose笔记(六十三)--SegmentedButton

这一节主要了解一下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 选项文本长度,选项文本尽量简短,避免换行。

相关推荐
阿巴斯甜17 小时前
Android 报错:Zip file '/Users/lyy/develop/repoAndroidLapp/l-app-android-ble/app/bu
android
Kapaseker18 小时前
实战 Compose 中的 IntrinsicSize
android·kotlin
xq952719 小时前
Andorid Google 登录接入文档
android
黄林晴20 小时前
告别 Modifier 地狱,Compose 样式系统要变天了
android·android jetpack
冬奇Lab1 天前
Android触摸事件分发、手势识别与输入优化实战
android·源码阅读
城东米粉儿1 天前
Android MediaPlayer 笔记
android
Jony_1 天前
Android 启动优化方案
android
阿巴斯甜1 天前
Android studio 报错:Cause: error=86, Bad CPU type in executable
android
张小潇1 天前
AOSP15 Input专题InputReader源码分析
android
_小马快跑_2 天前
Kotlin | 协程调度器选择:何时用CoroutineScope配置,何时用launch指定?
android