作成日 | 2025/06/23 |
最終更新日 | 2025/07/22 |
アプリを作っているときに、タップ以外の操作でスクロールを呼びたかった。
ボタンでスクロールできるようにしていきます。
ボタンでスクロールするためにはボタンが必要なので配置してあげます。差分は こちら です。Composeでボタンを置いただけです。clickableにしているのは、触っていることがわかりやすいようにするためです。
で、ボタンにスクロール機能を付けていきます。差分は こちら です。
タップでも長押しでもスクロールできるようにしてあげます。
ModifierExt.kt
fun Modifier.isPressed( buttonState: ButtonState, update: (ButtonState) -> Unit, ): Modifier { return this.pointerInput(Unit) { awaitEachGesture { awaitPointerEvent() update(buttonState) // 押されている間はtrue while ( awaitPointerEvent().changes.any { it.pressed } ) { // なにもしない } // 放されたらfalse update(ButtonState.None) } } }
ボタンの長押し検知用に作ったpointerInputです。
buttonStateがどのボタンが押しているかを指定し、updateで親で保持しているstateを更新します。
タップされたときに引数で指定されたボタンを押下状態にして、タップをやめたときにボタンの押下状態を解除します。
長押しを検知するModifierのcombinedClickableや 、PointerInput内で呼べるdetectTapGesturestがありますが [1] 、長押しになったことを検知するだけなので今回は使えません。
前に作ったのがpointerInputだったのでponiterInputを利用しましたが、pointerIntoropFilterというメソッドでも同様のことが出来そうです [2] 。
App.kt
@Composable @Preview fun App() { val scrollState = rememberLazyListState() var isButtonPressed by remember { mutableStateOf(ButtonState.None) } LaunchedEffect(isButtonPressed) { val delayTime = 100L var dif = 1 while (true) { when (isButtonPressed) { ButtonState.Up -> scrollState.animateScrollToItem( max( scrollState.firstVisibleItemIndex - dif, 0, ), ) ButtonState.Down -> scrollState.animateScrollToItem( scrollState.firstVisibleItemIndex + dif, ) ButtonState.None -> return@LaunchedEffect } delay(delayTime) dif++ } } ~省略~ }
ボタンの状態が変わったときに非同期処理が呼ばれ、押されている間は上下にスクロールし、放された場合なにもしません。
difは移動量です。上に移動するときは、先頭のアイテム番号を小さくし、下に移動するときは先頭のアイテムを大きくします。itemIndexが0になると困るので0にならないようにします。大きい方は問題ないです。
以上、スクロールを外部からいじる方法について調べ、リストのタップ操作以外でスクロールできるような実装をしました。
スクロールバーも別記事で作成している(こちら)ので、興味がある方はそちらもみてくださいませ。
ではまた。