ComposeではModifierを使ってクリックを処理する方法がいくつかありますので、それらをまとめておきます。
Modifier.clickable
clickable
は一番シンプルなクリックイベントを処理するものになります。
Box(
modifier = Modifier.clickable {
// クリックされたときの処理
}
)
この clickable
を適用すると自動的にクリック時にRipple Effectも行われるようになります。
Modifier.combinedClickable
単純なダブルクリックやロングクリックを処理する場合は combinedClickable
を使うことで簡単に実装できます。
Box(
modifier = Modifier
.combinedClickable(
onClick = {
// クリック
},
onDoubleClick = {
// ダブルクリック
},
onLongClick = {
// ロングクリック
}
)
)
こちらも clickable
と同様に自動でRipple Effectが行われるようになります。
注意としてはこれを書いてる時点ではExperimentalになっているため、今後変更される構成があります。
Modifier.pointerInput
最後に少し特殊な pointerInput
です。こちらはGesture全般を扱うことができます。今回は detectTapGestures
を使った処理を紹介します。他にも、 detectDragGestures
などもあります。
Box(
modifier = Modifier
.pointerInput(Unit) {
detectTapGestures(
onDoubleTap = {
},
onLongPress = {
},
onPress = {
},
onTap = {
}
)
},
)
pointerInput
内で detectTapGestures
関数の各引数でイベントを受け取ることができるようになっています。clickable
とは異なりこちらのほうは自動でRipple Effectを行われません。
また各イベントでは Offset
を受け取ることができるので、押された箇所がわかるようになっています。
この Offset
値はマイナス値や要素サイズより大きい値になる場合があります。(後述)
detectTapGestures(
onTap = {
val x = it.x
val y = it.y
},
)
さらに onPress
では押してる状態から離すまでを検知することができます。これを使って押してる間だけ表示を変えるようなことも可能です。
var pressing by remember { mutableStateOf(false) }
Box(
modifier = Modifier
.pointerInput(Unit) {
detectTapGestures(
onPress = {
// 押してる
pressing = true
tryAwaitRelease()
// 離した
pressing = false
},
)
},
)
押される間は tryAwaitRelease
で待つことになり、離されたときに後続の処理を実行します。また、戻り値でtrue/falseを返しますが、領域内で指を離したときはtrueを返しますが、押したまま領域の外に移動するとfalseを返します。
細かい制御ができるようになっています。
ViewConfigurationを使ったカスマイズ
ダブルクリックとして検知する間隔や、どれくらいの時間押していればダブルクリックと検知されるか、などを ViewConfiguration
を使ってカスマイズできるようになっています。
ViewConfiguration
を実装したクラスを作成して、それを CompositionLocal
を使って設定する感じなります。サンプルとしてデフォルト設定を活かしつつロングクリックと判定される時間を設定します。
// カスマイズしたViewConfiguration
class CustomViewConfiguration(
private val defaultViewConfiguration: ViewConfiguration // デフォルト
) : ViewConfiguration by defaultViewConfiguration {
// 3000ms押し続ければロングクリックとして判定
override val longPressTimeoutMillis: Long = 3000
}
@Composable
fun Sample() {
// デフォルトのViewConfigurationを取得
val defaultViewConfiguration = LocalViewConfiguration.current
val viewConfiguration = remember {
CustomViewConfiguration(defaultViewConfiguration)
}
CompositionLocalProvider(
LocalViewConfiguration provides viewConfiguration
) {
// ここの中はカスマイズされた値が使用される
Box(
modifier = Modifier
.combinedClickable(
onLongClick = {
// ...
},
)
)
}
}
また、 ViewConfiguration
では、最小のタップエリアも定義してます。このタップエリアより小さいサイズの要素は、 pointerInput
の処理は最小サイズの範囲で反応します。そのため、実際描画されてるエリアより広い範囲でタップイベントを検知することがあるので、 pointerInput
の処理で取得できるOffsetはマイナス値や要素サイズより大きい場合があります。
デフォルトでは48.dpになっているので、これを0.dpにすることで要素サイズが小さい場合でも、マイナス値や要素サイズを超えたOffset値は受け取らなくなります。
class CustomViewConfiguration(
private val defaultViewConfiguration: ViewConfiguration
) : ViewConfiguration by defaultViewConfiguration {
override val minimumTouchTargetSize: DpSize = DpSize(0.dp, 0.dp)
}
ViewConfiguration
の設定は、 combinedClickable
も pointerInput
も影響を受けます。