はじめに
以前の記事Jetpack Compose で Google Map内の操作と縦スクロールを共存させるでは、マップやグラフにタッチしている間だけ親のスクロールを無効にする方法を紹介しました。
前回の実装でタップ操作との共存はできたのですが、ドラッグ操作を加えたところ別の問題が起きたので紹介します。
前回のおさらい
タッチ中はスクロールを無効にするフラグを立て、verticalScroll の enabled で制御するパターンでした。
var isTouched by remember { mutableStateOf(false) }
Column(modifier = Modifier.verticalScroll(scrollState, enabled = !isTouched)) {
MyChart(onTouchChanged = { isTouched = it })
}
今回の問題
グラフ上で指をなぞる(ドラッグしてバーを選択する)操作を追加したところ、ドラッグ中に指を少し縦に動かすと親のスクロールが反応してしまう問題が起きました。
前回のフラグで verticalScrollは無効にしているはずなのになぜ?と思いましたが、原因は別のところにありました。
原因
onDrag コールバック内ではポインターイベントを消費していないためです。
Compose のジェスチャー処理はイベントが消費されていない場合、親のコンポーザブルにもそのイベントが伝播します。verticalScroll を無効にしていても、伝播したイベントが別の経路でスクロールを動かしてしまっていました。
解決策
結論から言いますと、change.consume() を呼ぶことです。
onDrag 内で change.consume() を呼ぶだけで解決します。
Modifier.pointerInput(values) {
detectDragGesturesAfterLongPress(
onDragStart = { ... },
onDrag = { change, _ ->
change.consume() // ← これで親への伝播を止める
val slot = barIndexFromOffset(change.position.x, ...)
selectedSlot = slot
},
)
}
これでドラッグ中のポインターイベントが処理済みとしてマークされ、親への伝播が止まります。
また、 前回のタッチフラグと今回の consume() は役割が異なるため、両方必要です。