0
点赞
收藏
分享

微信扫一扫

Android Compose实现Spinner

书坊尚 2022-03-11 阅读 51

在我写项目的时候要用到Spinner。找了找,目前compose里好像还没有类似Spinner的函数。使用AndroidView来使用Spinner的话又会出现一些问题。于是自己使用Compose实现了个简易的Spinner组件。

先写好Spinner函数

/**
 * @param modifier 应用于布局的修饰符
 * @param dataArray 数据数组
 * @param position 选择的item
 * @param expand 是否展开
 * @param arrowColor 下拉箭头颜色
 * @param arrowSize 下拉箭头大小
 * @param showHeight 下拉列表高度
 * @param enabled 是否启用
 * @param selectChange 选择item状态改变回调
 * @param expandChange 列表 展开/收起 状态改变会标
 * @param itemContent 描述item的Compose组件内容。lambda参数:data为数据(dataArray[index]),modifier里写好了用于监听item的点击选择回调
 */
@OptIn(ExperimentalAnimationApi::class)
@Composable
fun <T> Spinner(
    modifier: Modifier = Modifier,
    dataArray: Array<T>?,
    position: Int = 0,
    expand: Boolean = false,
    arrowColor: Color = LocalContentColor.current.copy(alpha = LocalContentAlpha.current),
    arrowSize: Dp = 30.dp,
    showHeight: Dp = 100.dp,
    enabled: Boolean = true,
    selectChange: (Int) -> Unit = {},
    expandChange: (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则是下拉箭头
下拉列表待会在加上
在这里插入图片描述

再然后将描述item的Compose组件内容lambda加到item父容器里面调用

//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)

写一个预览实例显示看看效果

看看效果
在这里插入图片描述
在这里插入图片描述

完整代码

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

/**
 * @param modifier 应用于布局的修饰符
 * @param dataArray 数据数组
 * @param position 选择的item
 * @param expanded 是否展开
 * @param arrowColor 下拉箭头颜色
 * @param arrowSize 下拉箭头大小
 * @param showHeight 下拉列表高度
 * @param enabled 是否启用
 * @param selectChange 选择item状态改变回调
 * @param expandedChange 列表 展开/收起 状态改变会标
 * @param itemContent 描述item的Compose组件内容。lambda参数:data为数据(dataArray[index]),modifier里写好了用于监听item的点击选择回调
 */
@OptIn(ExperimentalAnimationApi::class)
@Composable
fun <T> Spinner(
    modifier: Modifier = Modifier,
    dataArray: Array<T>?,
    position: Int = 0,
    expanded: Boolean = false,
    arrowColor: Color = LocalContentColor.current.copy(alpha = LocalContentAlpha.current),
    arrowSize: Dp = 30.dp,
    showHeight: Dp = 100.dp,
    enabled: Boolean = true,
    selectChange: (Int) -> 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.height(showHeight),
                    content = {
                        items(dataArray.size) {
                            itemContent.invoke(
                                dataArray[it],
                                Modifier.clickable(enabled = enabled) { selectChange.invoke(it) }
                            )
                        }
                    }
                )
            }
        }

        //禁用时收起下拉列表
        if (!enabled && expanded) expandedChange.invoke(false)
    }
}
举报

相关推荐

0 条评论