Compose笔记(三十七)--FilterChip
这一节主要了解一下Compose中的FilterChip,在Compose中,FilterChip是Material Design组件库提供的一种交互式芯片,主要用于提供多选或单选的筛选条件。简单总结如下
API
selected:控制Chip是否选中
onClick:点击事件回调
label:Chip显示的文本内容
leadingIcon:左侧图标
trailingIcon: 右侧图标(常用于显示选中状态)
colors:控制Chip在不同状态下的颜色
border:边框样式
shape:形状配置
enabled:是否可用状态
场景:
1. 内容筛选,适用于需要按类别、属性过滤列表/网格内容的场景
2. 标签式分类选择,适用于需要按标签对内容进行分类的场景,支持单选或多选
3. 状态切换型筛选,适用于需要按“状态”过滤内容的场景,状态通常是二元或少量固定选项
栗子:
import androidx.compose.foundation.layout.size
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Done
import androidx.compose.material.icons.filled.Home
import androidx.compose.material3.FilterChip
import androidx.compose.material3.FilterChipDefaults
import androidx.compose.material3.Icon
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier@Composable
fun TestFilterChipExample() {var selected by remember { mutableStateOf(false) }FilterChip( selected = selected,onClick = { selected = !selected },label = { Text("Filter chip") },leadingIcon = if (selected) { {Icon( imageVector = Icons. Filled.Done,contentDescription = "Localized Description",modifier = Modifier.size(FilterChipDefaults. IconSize)) } } else { {Icon( imageVector = Icons. Filled.Home,contentDescription = "Localized description",modifier = Modifier. size(FilterChipDefaults. IconSize))}} )
}
import android.annotation.SuppressLint
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.text.KeyboardActions
import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Done
import androidx.compose.material3.*
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.input.ImeAction
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.spdata class Article(val id: String,val title: String,val tags: List<String>
)@SuppressLint("UnrememberedMutableState")
@OptIn(ExperimentalMaterial3Api::class, ExperimentalLayoutApi::class)
@Composable
fun TestTagFilterExample() {val articles = remember {listOf(Article("1", "Jetpack Compose基础", listOf("Android", "Compose")),Article("2", "Kotlin协程", listOf("Kotlin", "协程")),Article("3", "Material3设计规范", listOf("Android", "UI")),Article("4", "Compose状态管理", listOf("Android", "Compose", "状态管理")))}val allTags = remember {articles.flatMap { it.tags }.distinct().toMutableStateList()}var selectedTags by remember { mutableStateOf(setOf<String>()) }var newTag by remember { mutableStateOf("") }val filteredArticles by derivedStateOf {if (selectedTags.isEmpty()) articleselse articles.filter { article ->article.tags.any { selectedTags.contains(it) }}}Column(modifier = Modifier.fillMaxSize()) {Text(text = "文章标签筛选",fontSize = 20.sp,fontWeight = FontWeight.Bold,modifier = Modifier.padding(16.dp))Row(modifier = Modifier.padding(16.dp),verticalAlignment = Alignment.CenterVertically) {OutlinedTextField(value = newTag,onValueChange = { newTag = it },label = { Text("添加新标签") },modifier = Modifier.weight(1f),singleLine = true,keyboardOptions = KeyboardOptions(imeAction = ImeAction.Done),keyboardActions = KeyboardActions(onDone = {if (newTag.isNotBlank() && !allTags.contains(newTag)) {allTags.add(newTag)newTag = ""}}))Button(onClick = {if (newTag.isNotBlank() && !allTags.contains(newTag)) {allTags.add(newTag)newTag = ""}},modifier = Modifier.padding(start = 8.dp),enabled = newTag.isNotBlank()) {Text("添加")}}Text(text = "标签列表",fontWeight = FontWeight.Medium,modifier = Modifier.padding(16.dp, 8.dp, 16.dp, 0.dp))FlowRow(modifier = Modifier.padding(12.dp),horizontalArrangement = Arrangement.spacedBy(8.dp),verticalArrangement = Arrangement.spacedBy(8.dp)) {allTags.forEach { tag ->val isSelected = selectedTags.contains(tag)FilterChip(selected = isSelected,onClick = {selectedTags = if (isSelected) {selectedTags - tag} else {selectedTags + tag}},label = { Text(tag) },leadingIcon = if (isSelected) {{Icon(imageVector = Icons.Filled.Done,contentDescription = "已选择",modifier = Modifier.size(FilterChipDefaults.IconSize))}} else null,colors = FilterChipDefaults.filterChipColors(containerColor = if (isSelected)MaterialTheme.colorScheme.primaryContainerelse MaterialTheme.colorScheme.surface,labelColor = if (isSelected)MaterialTheme.colorScheme.onPrimaryContainerelse MaterialTheme.colorScheme.onSurface,iconColor = MaterialTheme.colorScheme.onPrimaryContainer),border = FilterChipDefaults.filterChipBorder(borderColor = MaterialTheme.colorScheme.outline,borderWidth = 1.dp,enabled = true,selected = isSelected,selectedBorderColor = MaterialTheme.colorScheme.primary,disabledBorderColor = MaterialTheme.colorScheme.outline.copy(alpha = 0.38f),disabledSelectedBorderColor = MaterialTheme.colorScheme.onSurface.copy(alpha = 0.38f),selectedBorderWidth = 1.dp),shape = MaterialTheme.shapes.small)}}Text(text = "筛选结果 (${filteredArticles.size})",fontWeight = FontWeight.Medium,modifier = Modifier.padding(16.dp))LazyColumn(modifier = Modifier.weight(1f)) {items(filteredArticles) { article ->Card(modifier = Modifier.fillMaxWidth().padding(12.dp),elevation = CardDefaults.cardElevation(defaultElevation = 2.dp)) {Column(modifier = Modifier.padding(16.dp)) {Text(text = article.title,fontWeight = FontWeight.Bold,fontSize = 16.sp)Spacer(modifier = Modifier.height(8.dp))FlowRow(horizontalArrangement = Arrangement.spacedBy(4.dp)) {article.tags.forEach { tag ->Box(modifier = Modifier.background(if (selectedTags.contains(tag))MaterialTheme.colorScheme.primaryContainerelse MaterialTheme.colorScheme.surfaceVariant,shape = MaterialTheme.shapes.small).padding(4.dp, 2.dp)) {Text(text = tag,fontSize = 12.sp,color = if (selectedTags.contains(tag))MaterialTheme.colorScheme.onPrimaryContainerelse MaterialTheme.colorScheme.onSurfaceVariant)}}}}}}}}
}
注意:
1 明确“选中即生效”的设计原则,避免将其用于“需要批量选择后统一生效”的场景,选中状态变化时,应立即更新筛选结果
2 区分“单选”和“多选”场景,多选场景:允许同时选中多个芯片,筛选逻辑为 “满足任一条件”;单选场景:选中新芯片时,需自动取消同组其他芯片的选中状态。
3 正确处理FilterChipDefaults参数,Material 3的FilterChip参数严格,需注意border参数需指定所有状态(选中/未选中/禁用)的边框样式,colors参数需区分容器色(containerColor)和内容色(labelColor),