0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Jetpack ComposeでnumberPicker(ナンバーピッカー)を実装する

Posted at

実践

@OptIn(ExperimentalFoundationApi::class)
@Composable
fun ScrollPicker(
    items: List<String>,
    modifier: Modifier = Modifier,
    onSelected: (String) -> Unit
) {
    val listState = rememberLazyListState()
    val itemHeight = 50.dp
    val itemHeightPx = with(LocalDensity.current) { itemHeight.toPx() }
    val flingBehavior = rememberSnapFlingBehavior(listState)

    LaunchedEffect(listState.firstVisibleItemIndex, listState.firstVisibleItemScrollOffset) {
        val index = listState.firstVisibleItemIndex +
                if (listState.firstVisibleItemScrollOffset > itemHeightPx / 2) 1 else 0

        if (index in items.indices) {
            onSelected(items[index])
        }
    }

    Box(
        modifier = modifier
            .height(itemHeight * 3) // 中央表示のため3行分
            .fillMaxWidth()
    ) {
        LazyColumn(
            state = listState,
            flingBehavior = flingBehavior,
            modifier = Modifier.fillMaxSize(),
            horizontalAlignment = Alignment.CenterHorizontally
        ) {
            items(items.size) { i ->
                Box(
                    modifier = Modifier
                        .height(itemHeight)
                        .fillMaxWidth(),
                    contentAlignment = Alignment.Center
                ) {
                    Text(
                        text = items[i],
                        fontSize = 20.sp
                    )
                }
            }
        }

        // 中央の選択ライン
        Box(
            modifier = Modifier
                .align(Alignment.Center)
                .fillMaxWidth()
                .height(48.dp)
                .border(1.dp, Color.Gray, RectangleShape)
        )
    }
}

使用例

@Composable
fun ExampleScreen() {
    var selected by remember { mutableStateOf("0") }

    ScrollPicker(
        items = (0..59).map { it.toString().padStart(2, '0') },
        modifier = Modifier.fillMaxWidth(),
        onSelected = { selected = it }
    )

    Text("選択中: $selected")
}

説明

flingBehavior

でスナップショット(ピタッと止まる)の挙動を管理してます。

        // 中央の選択ライン
        Box(
            modifier = Modifier
                .align(Alignment.Center)
                .fillMaxWidth()
                .height(48.dp)
                .border(1.dp, Color.Gray, RectangleShape)
        )
    }

Compose側で真ん中にあるものを選択状態にしてくれるわけではないので、真ん中にある数字を選択中に見えるようにしてあります。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?