You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Jetpack Compose中实现数字选择器?含库集成及原生实现示例

Jetpack Compose 数字选择器实现方案

一、添加第三方库 Compose-NumberPicker

  1. 确保项目依赖仓库包含Maven Central,在settings.gradle中配置:
dependencyResolutionManagement {
    repositories {
        // 保留原有仓库,新增以下行
        mavenCentral()
    }
}
  1. 在模块级build.gradle.kts(或build.gradle)中添加依赖,将latest-version替换为仓库最新版本号:
dependencies {
    implementation "com.chargemap.compose:numberpicker:latest-version"
}
  1. 基础使用示例:
var selectedNumber by remember { mutableStateOf(5) }

BasicNumberPicker(
    value = selectedNumber,
    onValueChange = { selectedNumber = it },
    range = 0..10,
)

二、不依赖第三方库的原生实现

方案1:滚轮式数字选择器

基于LazyColumn实现滚动选中逻辑,支持范围限制与选中项高亮:

@Composable
fun CustomWheelNumberPicker(
    minValue: Int,
    maxValue: Int,
    initialValue: Int,
    onValueChange: (Int) -> Unit
) {
    var selectedValue by remember { mutableStateOf(initialValue.coerceIn(minValue, maxValue)) }
    val listState = rememberLazyListState(
        initialFirstVisibleItemIndex = selectedValue - minValue
    )

    // 滚动时同步选中值
    LaunchedEffect(listState.firstVisibleItemIndex) {
        val newValue = minValue + listState.firstVisibleItemIndex
        if (newValue != selectedValue) {
            selectedValue = newValue
            onValueChange(newValue)
        }
    }

    Column(
        modifier = Modifier
            .width(100.dp)
            .height(150.dp)
            .clip(RoundedCornerShape(8.dp))
            .border(1.dp, Color.Gray, RoundedCornerShape(8.dp))
            .padding(vertical = 8.dp),
        horizontalAlignment = Alignment.CenterHorizontally
    ) {
        // 选中项边框指示器
        Box(
            modifier = Modifier
                .fillMaxWidth()
                .height(50.dp)
                .border(top = 1.dp, bottom = 1.dp, color = Color.Blue)
        )

        LazyColumn(
            state = listState,
            horizontalAlignment = Alignment.CenterHorizontally,
            modifier = Modifier
                .fillMaxSize()
                .layout { measurable, constraints ->
                    val placeable = measurable.measure(constraints)
                    layout(placeable.width, placeable.height) {
                        // 让列表初始滚动到选中项居中位置
                        placeable.placeRelative(0, (placeable.height / 2) - (50.dp.roundToPx() / 2))
                    }
                }
        ) {
            items(maxValue - minValue + 1) { index ->
                val value = minValue + index
                Text(
                    text = value.toString(),
                    fontSize = if (value == selectedValue) 20.sp else 16.sp,
                    fontWeight = if (value == selectedValue) FontWeight.Bold else FontWeight.Normal,
                    color = if (value == selectedValue) Color.Blue else Color.Black,
                    modifier = Modifier
                        .padding(vertical = 16.dp)
                        .width(80.dp)
                        .height(50.dp)
                        .wrapContentHeight()
                )
            }
        }
    }
}

// 使用示例
@Composable
fun WheelPickerDemo() {
    var selectedNumber by remember { mutableStateOf(5) }

    Column(
        modifier = Modifier.fillMaxSize(),
        verticalArrangement = Arrangement.Center,
        horizontalAlignment = Alignment.CenterHorizontally
    ) {
        CustomWheelNumberPicker(
            minValue = 0,
            maxValue = 10,
            initialValue = selectedNumber,
            onValueChange = { selectedNumber = it }
        )
        Spacer(modifier = Modifier.height(20.dp))
        Text(text = "选中值: $selectedNumber")
    }
}

方案2:按钮控制式数字选择器

适合需要点击上下箭头调整数值的场景:

@Composable
fun ButtonControlNumberPicker(
    minValue: Int,
    maxValue: Int,
    initialValue: Int,
    onValueChange: (Int) -> Unit
) {
    var selectedValue by remember { mutableStateOf(initialValue.coerceIn(minValue, maxValue)) }

    Column(
        horizontalAlignment = Alignment.CenterHorizontally,
        verticalArrangement = Arrangement.SpaceBetween,
        modifier = Modifier
            .width(80.dp)
            .height(150.dp)
            .border(1.dp, Color.Gray, RoundedCornerShape(8.dp))
            .padding(8.dp)
    ) {
        IconButton(
            onClick = {
                if (selectedValue < maxValue) {
                    selectedValue++
                    onValueChange(selectedValue)
                }
            },
            enabled = selectedValue < maxValue
        ) {
            Icon(Icons.Default.ArrowDropUp, contentDescription = "增加数值")
        }

        Text(
            text = selectedValue.toString(),
            fontSize = 24.sp,
            fontWeight = FontWeight.Bold
        )

        IconButton(
            onClick = {
                if (selectedValue > minValue) {
                    selectedValue--
                    onValueChange(selectedValue)
                }
            },
            enabled = selectedValue > minValue
        ) {
            Icon(Icons.Default.ArrowDropDown, contentDescription = "减少数值")
        }
    }
}

// 使用示例
@Composable
fun ButtonPickerDemo() {
    var selectedNumber by remember { mutableStateOf(3) }

    Column(
        modifier = Modifier.fillMaxSize(),
        verticalArrangement = Arrangement.Center,
        horizontalAlignment = Alignment.CenterHorizontally
    ) {
        ButtonControlNumberPicker(
            minValue = 0,
            maxValue = 10,
            initialValue = selectedNumber,
            onValueChange = { selectedNumber = it }
        )
        Spacer(modifier = Modifier.height(20.dp))
        Text(text = "当前选中: $selectedNumber")
    }
}

内容的提问来源于stack exchange,提问作者NewPartizal

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.02 04:30:41