观心静

  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

声明

本文来自博客园,作者:观心静 ,转载请注明原文链接:https://www.cnblogs.com/guanxinjing/p/19315947

本文版权归作者和博客园共有,欢迎转载,但必须给出原文链接,并保留此段声明,否则保留追究法律责任的权利。

前言

   支持选中放大和自动回正

效果图

image

代码


import android.util.Log
import androidx.compose.foundation.gestures.snapping.rememberSnapFlingBehavior
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.itemsIndexed
import androidx.compose.foundation.lazy.rememberLazyListState
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.derivedStateOf
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.scale
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.layout.onSizeChanged
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.TextUnit
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import kotlinx.coroutines.delay

/**
 * 滚轮选择器组件
 *
 * @param items 选项列表
 * @param defaultSelectedIndex 默认选中的索引
 * @param itemHeight 每个选项的高度
 * @param itemFontSize 选项文字大小
 * @param visibleItemsCount 可见选项数量(必现是奇数)
 * @param selectTextColor 选中项文字颜色
 * @param notSelectTextColor 未选中项文字颜色
 * @param modifier 修饰符
 * @param onSelectedIndex 选中索引变化回调函数
 */
@Composable
fun WheelPicker(
    items: List<String>,
    defaultSelectedIndex: Int = 0,
    itemHeight: Dp = 50.dp,
    itemFontSize: TextUnit = 22.sp,
    visibleItemsCount: Int = 5,
    selectTextColor:Color = Color.Black,
    notSelectTextColor:Color = Color.Gray,
    modifier: Modifier = Modifier,
    onSelectedIndex: (Int) -> Unit
) {
    // 计算需要在列表两端添加的空白项数量,使选中项能够居中显示
    val paddingCount = (visibleItemsCount - 1) / 2
    // 计算实际选中项在扩展后列表中的索引位置
    val selectedIndex = defaultSelectedIndex + 2
    // 创建带有前后填充空项的数据列表,使其可以在居中的情况下选中items里的第一个数据和最后一个数据
    val dataList = remember(items) {
        List(paddingCount) { "" } + items + List(paddingCount) { "" }
    }
    var listHeight by remember { mutableStateOf(0) }

    val listState = rememberLazyListState(
        initialFirstVisibleItemIndex = (selectedIndex - visibleItemsCount / 2)
            .coerceIn(0, dataList.size - visibleItemsCount)
    )

    // 计算当前居中选中的index
    val centerIndex = remember {
        derivedStateOf {
            val visibleItems = listState.layoutInfo.visibleItemsInfo
            if (visibleItems.isEmpty()) return@derivedStateOf 0
            val centerPosition = listHeight / 2
            val closestItem = visibleItems.minByOrNull { item ->
                val itemCenter = item.offset + item.size / 2
                kotlin.math.abs(itemCenter - centerPosition)
            }
            closestItem?.index ?: 0
        }
    }

    // 使用LaunchedEffect监听滚动状态变化,确保在滚动停止后更新选中项
    LaunchedEffect(listState.isScrollInProgress) {
        if (!listState.isScrollInProgress) {
            // 滚动停止后,延迟一小段时间以确保最终位置稳定
            delay(100)
            val currentIndex = centerIndex.value.coerceIn(0, dataList.size - 1)
            if (currentIndex < dataList.size) {
                Log.e("zh", "当前居中选中的index >> ${currentIndex - paddingCount}")
                onSelectedIndex(currentIndex - paddingCount)
            }
        }
    }

    Box(modifier = modifier.height(itemHeight * visibleItemsCount)) {
        LazyColumn(
            state = listState,
            flingBehavior = rememberSnapFlingBehavior(listState),
            horizontalAlignment = Alignment.CenterHorizontally,
            modifier = Modifier
                .fillMaxSize()
                .onSizeChanged {
                    listHeight = it.height
                }
        ) {
            itemsIndexed(dataList) { index, item ->
                Text(
                    text = item,
                    fontSize = itemFontSize,
                    color = if (index == centerIndex.value) selectTextColor else notSelectTextColor,
                    textAlign = TextAlign.Center,
                    modifier = Modifier
                        .height(itemHeight)
                        .padding(horizontal = 16.dp)
                        .scale(if (index == centerIndex.value) 1.5f else 1f)
                )
            }
        }
    }
}

 

 

 

end

 

posted on 2025-12-06 15:49  观心静  阅读(3)  评论(0)    收藏  举报