在我写项目的时候要用到Spinner。找了找,目前compose里好像还没有类似Spinner的函数。使用AndroidView来使用Spinner的话又会出现一些问题。于是自己使用Compose实现了个简易的Spinner组件。
先写好Spinner函数@OptIn(ExperimentalAnimationApi::class) @Composable funSpinner( modifier: Modifier = Modifier, dataArray: Array ?, position: Int = 0, expanded: Boolean = false, arrowColor: Color = LocalContentColor.current.copy(alpha = LocalContentAlpha.current), arrowSize: Dp = 30.dp, maxShowHeight: Dp = 100.dp, enabled: Boolean = true, selectChange: (Int, T) -> Unit = { _,_ -> }, expandedChange: (Boolean) -> Unit = {}, itemContent: @Composable (data: T, modifier: Modifier) -> Unit, ) { }
后面代码中用到了实验性api:AnimatedVisibility,要加入@OptIn(ExperimentalAnimationApi::class)
然后写好Spinner的轮廓Column(modifier = modifier) {
Row(modifier = Modifier.clickable(enabled = enabled) { expandedChange.invoke(!expanded) }) {
//item父容器
Box(modifier = Modifier.align(Alignment.CenterVertically)) {
//item组件
}
//下拉箭头
Icon(
imageVector = Icons.Default.ArrowDropDown,
contentDescription = if (expanded) "下拉" else "上拉",
tint = arrowColor,
modifier = Modifier
.size(arrowSize)
.align(Alignment.CenterVertically)
.rotate(degrees)
)
}
//下拉列表
}
Column作为最外层的容器,包住Spinner的选中内容和下拉列表。
Row里有左右两个东西,item和下拉箭头
Box包住item方便控制摆放位置
Icon则是下拉箭头
下拉列表待会在加上
//dataArray为空时使用Spacer占位
if (dataArray == null) {
Spacer(modifier = Modifier.size(width = 100.dp, height = 38.dp))
} else {
//调用itemContent显示item
itemContent.invoke(dataArray[position], Modifier)
}
最后将下拉列表加到Row的下面就好了
//dataArray不为空时才显示下拉列表
if (dataArray != null) {
//显示/隐藏动画
AnimatedVisibility(expanded) {
LazyColumn(modifier = Modifier.height(showHeight),
content = {
items(dataArray.size) {
itemContent.invoke(
dataArray[it],
Modifier.clickable(enabled = enabled) { selectChange.invoke(it) }
)
}
}
)
}
}
//禁用时收起下拉列表
if (!enabled && expanded) expandedChange.invoke(false)
写一个预览实例显示看看效果
@Preview
@Composable
fun SpinnerPreview() {
val dataArray = arrayOf("Test1", "Test2", "Test3")
var position: Int by remember { mutableStateOf(0) }
var expanded: Boolean by remember{ mutableStateOf(false) }
Spinner(
modifier = Modifier.background(Color.White),
dataArray = dataArray,
position = position,
expanded = expanded,
selectChange = { i, data ->
position = i
},
expandedChange = {
expanded = it
}
) { data, modifier ->
Text(text = data, modifier)
}
}
看看效果
import androidx.compose.animation.AnimatedVisibility import androidx.compose.animation.ExperimentalAnimationApi import androidx.compose.animation.core.animateFloatAsState import androidx.compose.foundation.background import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.* import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.material.* import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.ArrowDropDown import androidx.compose.runtime.* import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.rotate import androidx.compose.ui.graphics.Color import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.dp @OptIn(ExperimentalAnimationApi::class) @Composable funSpinner( modifier: Modifier = Modifier, dataArray: Array ?, position: Int = 0, expanded: Boolean = false, arrowColor: Color = LocalContentColor.current.copy(alpha = LocalContentAlpha.current), arrowSize: Dp = 30.dp, maxShowHeight: Dp = 100.dp, enabled: Boolean = true, selectChange: (Int, T) -> Unit = { _,_ -> }, expandedChange: (Boolean) -> Unit = {}, itemContent: @Composable (data: T, modifier: Modifier) -> Unit, ) { //下拉箭头旋转角度 val degrees: Float by animateFloatAsState(targetValue = if (expanded) 0f else 90f) Column(modifier = modifier) { Row(modifier = Modifier.clickable(enabled = enabled) { expandedChange.invoke(!expanded) }) { Box(modifier = Modifier.align(Alignment.CenterVertically)) { //dataArray为空时使用Spacer占位 if (dataArray == null) { Spacer(modifier = Modifier.size(width = 100.dp, height = 38.dp)) } else { //调用itemContent显示item itemContent.invoke(dataArray[position], Modifier) } } Icon( imageVector = Icons.Default.ArrowDropDown, contentDescription = if (expanded) "下拉" else "收起", tint = arrowColor, modifier = Modifier .size(arrowSize) .align(Alignment.CenterVertically) .rotate(degrees) ) } //dataArray不为空时才显示下拉列表 if (dataArray != null) { //显示/隐藏动画 AnimatedVisibility(expanded) { LazyColumn(modifier = Modifier.heightIn(max = maxShowHeight), content = { items(dataArray.size) { itemContent.invoke( dataArray[it], Modifier.clickable(enabled = enabled) { selectChange.invoke(it, dataArray[it]) } ) } } ) } } //禁用时收起下拉列表 if (!enabled && expanded) expandedChange.invoke(false) } }



