タップして押す
コレクションでコンテンツを整理
必要に応じて、コンテンツの保存と分類を行います。
多くのコンポーザブルには、タップやクリックのサポートが組み込まれており、onClick
ラムダが含まれています。たとえば、サーフェスとのインタラクションに適したすべてのマテリアル デザインの動作を含む、クリック可能な Surface
を作成できます。
Surface(onClick = { /* handle click */ }) {
Text("Click me!", Modifier.padding(24.dp))
}
ただし、ユーザーがコンポーザブルを操作する方法はクリックだけではありません。このページでは、1 つのポインタが関与するジェスチャーについて説明します。この場合、そのポインタの位置はイベントの処理に重要ではありません。次の表に、これらの種類のジェスチャーを示します。
ジェスチャー |
説明 |
タップ(またはクリック) |
ポインタが下に移動してから上に移動する |
ダブルタップ |
ポインタが下、上、下、上の順に移動する |
長押し |
ポインタが下がり、長時間保持される |
プレス |
ポインタが下がる |
タップまたはクリックに応答する
clickable
は、タップやクリックにコンポーザブルを反応させるためによく使用される修飾子です。この修飾子には、フォーカス、マウスやタッチペンのホバー、押下時のカスタマイズ可能な視覚的な表示のサポートなど、追加機能も含まれています。この修飾子は、広い意味での「クリック」に反応します。マウスや指によるクリックだけでなく、キーボード入力によるクリック イベントやユーザー補助サービス使用時のクリック イベントにも反応します。
画像のグリッドを想像してみてください。ユーザーが画像をクリックすると、その画像が全画面表示されます。
この動作を実装するには、グリッド内の各アイテムに clickable
修飾子を追加します。
@Composable
private fun ImageGrid(photos: List<Photo>) {
var activePhotoId by rememberSaveable { mutableStateOf<Int?>(null) }
LazyVerticalGrid(columns = GridCells.Adaptive(minSize = 128.dp)) {
items(photos, { it.id }) { photo ->
ImageItem(
photo,
Modifier.clickable { activePhotoId = photo.id }
)
}
}
if (activePhotoId != null) {
FullScreenImage(
photo = photos.first { it.id == activePhotoId },
onDismiss = { activePhotoId = null }
)
}
}
clickable
修飾子を使用すると、追加の動作も追加されます。
interactionSource
と indication
。ユーザーがコンポーザブルをタップすると、デフォルトでリップルが描画されます。これらのカスタマイズ方法については、ユーザー操作の処理をご覧ください。
- ユーザー補助サービスがセマンティクス情報を設定して要素を操作できるようにします。
- キーボードまたはジョイスティックによる操作をサポートします。フォーカスを設定したり、
Enter
キーまたは D-pad の中央を押したりすることで操作できます。
- 要素をホバー可能にして、マウスやタッチペンがホバーしたときに応答するようにします。
長押ししてコンテキスト メニューを表示する
combinedClickable
を使用すると、通常のクリック動作に加えて、ダブルタップや長押しの動作を追加できます。combinedClickable
を使用すると、ユーザーがグリッド画像を長押ししたときにコンテキスト メニューを表示できます。
var contextMenuPhotoId by rememberSaveable { mutableStateOf<Int?>(null) }
val haptics = LocalHapticFeedback.current
LazyVerticalGrid(columns = GridCells.Adaptive(minSize = 128.dp)) {
items(photos, { it.id }) { photo ->
ImageItem(
photo,
Modifier
.combinedClickable(
onClick = { activePhotoId = photo.id },
onLongClick = {
haptics.performHapticFeedback(HapticFeedbackType.LongPress)
contextMenuPhotoId = photo.id
},
onLongClickLabel = stringResource(R.string.open_context_menu)
)
)
}
}
if (contextMenuPhotoId != null) {
PhotoActionsSheet(
photo = photos.first { it.id == contextMenuPhotoId },
onDismissSheet = { contextMenuPhotoId = null }
)
}
ユーザーが要素を長押ししたときに触覚フィードバックを追加することをおすすめします。そのため、このスニペットには performHapticFeedback
呼び出しが含まれています。
スクリムをタップしてコンポーザブルを閉じる
上記の例では、clickable
と combinedClickable
はコンポーザブルに便利な機能を追加します。操作時に視覚的なインジケーターを表示し、ホバーに応答します。また、フォーカス、キーボード、ユーザー補助のサポートも含まれています。ただし、この追加動作が望ましいとは限りません。
画像の詳細画面を見てみましょう。背景は半透明にする必要があります。また、ユーザーがその背景をタップして詳細画面を閉じられる必要があります。
この場合、その背景にはインタラクションに関する視覚的な表示がなく、ホバーに応答せず、フォーカス可能ではなく、キーボード イベントとユーザー補助イベントに対するレスポンスは一般的なコンポーザブルとは異なります。clickable
の動作を適応させる代わりに、抽象化レベルを下げて、detectTapGestures
メソッドと組み合わせて pointerInput
修飾子を直接使用できます。
@Composable
private fun Scrim(onClose: () -> Unit, modifier: Modifier = Modifier) {
val strClose = stringResource(R.string.close)
Box(
modifier
// handle pointer input
.pointerInput(onClose) { detectTapGestures { onClose() } }
// handle accessibility services
.semantics(mergeDescendants = true) {
contentDescription = strClose
onClick {
onClose()
true
}
}
// handle physical keyboard input
.onKeyEvent {
if (it.key == Key.Escape) {
onClose()
true
} else {
false
}
}
// draw scrim
.background(Color.DarkGray.copy(alpha = 0.75f))
)
}
pointerInput
修飾子のキーとして、onClose
ラムダを渡します。これにより、ラムダが自動的に再実行され、ユーザーがスクリームをタップしたときに適切なコールバックが呼び出されます。
ダブルタップしてズーム
clickable
と combinedClickable
に、インタラクションに正しく応答するのに十分な情報が含まれていない場合があります。たとえば、コンポーザブルは、コンポーザブルの境界内でインタラクションが発生した位置にアクセスする必要がある場合があります。
画像の詳細画面をもう一度見てみましょう。ダブルタップして画像を拡大できるようにすることをおすすめします。
動画でわかるように、タップ イベントの位置を中心にズームインします。画像の左側と右側をズームインした場合の結果は異なります。pointerInput
修飾子と detectTapGestures
を組み合わせて、タップ位置を計算に組み込むことができます。
var zoomed by remember { mutableStateOf(false) }
var zoomOffset by remember { mutableStateOf(Offset.Zero) }
Image(
painter = rememberAsyncImagePainter(model = photo.highResUrl),
contentDescription = null,
modifier = modifier
.pointerInput(Unit) {
detectTapGestures(
onDoubleTap = { tapOffset ->
zoomOffset = if (zoomed) Offset.Zero else
calculateOffset(tapOffset, size)
zoomed = !zoomed
}
)
}
.graphicsLayer {
scaleX = if (zoomed) 2f else 1f
scaleY = if (zoomed) 2f else 1f
translationX = zoomOffset.x
translationY = zoomOffset.y
}
)
あなたへのおすすめ
このページのコンテンツやコードサンプルは、コンテンツ ライセンスに記載のライセンスに従います。Java および OpenJDK は Oracle および関連会社の商標または登録商標です。
最終更新日 2025-08-23 UTC。
[[["わかりやすい","easyToUnderstand","thumb-up"],["問題の解決に役立った","solvedMyProblem","thumb-up"],["その他","otherUp","thumb-up"]],[["必要な情報がない","missingTheInformationINeed","thumb-down"],["複雑すぎる / 手順が多すぎる","tooComplicatedTooManySteps","thumb-down"],["最新ではない","outOfDate","thumb-down"],["翻訳に関する問題","translationIssue","thumb-down"],["サンプル / コードに問題がある","samplesCodeIssue","thumb-down"],["その他","otherDown","thumb-down"]],["最終更新日 2025-08-23 UTC。"],[],[],null,["# Tap and press\n\nMany composables have built-in support for taps or clicks and include an\n`onClick` lambda. For example, you can create a clickable `Surface` that\nincludes all Material Design behavior appropriate for interaction with surfaces:\n\n\n```kotlin\nSurface(onClick = { /* handle click */ }) {\n Text(\"Click me!\", Modifier.padding(24.dp))\n}https://github.com/android/snippets/blob/dd30aee903e8c247786c064faab1a9ca8d10b46e/compose/snippets/src/main/java/com/example/compose/snippets/touchinput/pointerinput/TapAndPress.kt#L111-L113\n```\n\n\u003cbr /\u003e\n\nBut clicks are not the only way a user can interact with composables. This page\nfocuses on gestures that involve a single pointer, where the position of\nthat pointer is not significant for the handling of that event. The following\ntable lists these types of gestures:\n\n|----------------|--------------------------------------------------|\n| **Gesture** | **Description** |\n| Tap (or click) | Pointer goes down and then up |\n| Double tap | Pointer goes down, up, down, up |\n| Long-press | Pointer goes down, and is held for a longer time |\n| Press | Pointer goes down |\n\nRespond to tap or click\n-----------------------\n\n[`clickable`](/reference/kotlin/androidx/compose/foundation/package-summary#(androidx.compose.ui.Modifier).clickable(kotlin.Boolean,kotlin.String,androidx.compose.ui.semantics.Role,kotlin.Function0)) is a commonly used modifier that makes a composable react to\ntaps or clicks. This modifier also adds additional features, such as support for\nfocus, mouse and stylus hovering, and a customizable visual indication when\npressed. The modifier responds to \"clicks\" in the widest sense of the word-- not\nonly with mouse or finger, but also click events through keyboard input or when\nusing accessibility services.\n\nImagine a grid of images, where an image shows full-screen when a user\nclicks on it:\n\nYou can add the `clickable` modifier to each item in the grid to implement this\nbehavior:\n\n\n```kotlin\n@Composable\nprivate fun ImageGrid(photos: List\u003cPhoto\u003e) {\n var activePhotoId by rememberSaveable { mutableStateOf\u003cInt?\u003e(null) }\n LazyVerticalGrid(columns = GridCells.Adaptive(minSize = 128.dp)) {\n items(photos, { it.id }) { photo -\u003e\n ImageItem(\n photo,\n Modifier.clickable { activePhotoId = photo.id }\n )\n }\n }\n if (activePhotoId != null) {\n FullScreenImage(\n photo = photos.first { it.id == activePhotoId },\n onDismiss = { activePhotoId = null }\n )\n }\n}https://github.com/android/snippets/blob/dd30aee903e8c247786c064faab1a9ca8d10b46e/compose/snippets/src/main/java/com/example/compose/snippets/touchinput/pointerinput/TapAndPress.kt#L119-L138\n```\n\n\u003cbr /\u003e\n\nThe `clickable` modifier also adds additional behavior:\n\n- `interactionSource` and `indication`, which draw a ripple by default when a user taps the composable. Learn how to customize these on the [Handling user\n interactions](/develop/ui/compose/touch-input/user-interactions/handling-interactions) page.\n- Allows accessibility services to interact with the element by setting the semantics information.\n- Supports keyboard or joystick interaction by allowing focus and pressing `Enter` or the center of the d-pad to interact.\n- Make the element hoverable, so it responds to the mouse or stylus hovering over it.\n\nLong-press to show a contextual context menu\n--------------------------------------------\n\n[`combinedClickable`](/reference/kotlin/androidx/compose/foundation/package-summary#(androidx.compose.ui.Modifier).combinedClickable(androidx.compose.foundation.interaction.MutableInteractionSource,androidx.compose.foundation.Indication,kotlin.Boolean,kotlin.String,androidx.compose.ui.semantics.Role,kotlin.String,kotlin.Function0,kotlin.Function0,kotlin.Function0)) lets you add double tap or long-press behavior in\naddition to normal click behavior. You can use `combinedClickable` to show a\ncontext menu when a user touches and holds a grid image:\n\n\n```kotlin\nvar contextMenuPhotoId by rememberSaveable { mutableStateOf\u003cInt?\u003e(null) }\nval haptics = LocalHapticFeedback.current\nLazyVerticalGrid(columns = GridCells.Adaptive(minSize = 128.dp)) {\n items(photos, { it.id }) { photo -\u003e\n ImageItem(\n photo,\n Modifier\n .combinedClickable(\n onClick = { activePhotoId = photo.id },\n onLongClick = {\n haptics.performHapticFeedback(HapticFeedbackType.LongPress)\n contextMenuPhotoId = photo.id\n },\n onLongClickLabel = stringResource(R.string.open_context_menu)\n )\n )\n }\n}\nif (contextMenuPhotoId != null) {\n PhotoActionsSheet(\n photo = photos.first { it.id == contextMenuPhotoId },\n onDismissSheet = { contextMenuPhotoId = null }\n )\n}https://github.com/android/snippets/blob/dd30aee903e8c247786c064faab1a9ca8d10b46e/compose/snippets/src/main/java/com/example/compose/snippets/touchinput/pointerinput/TapAndPress.kt#L146-L171\n```\n\n\u003cbr /\u003e\n\nAs a best practice, you should include haptic feedback when the user\nlong-presses elements, which is why the snippet includes the\n`performHapticFeedback` invocation.\n\nDismiss a composable by tapping a scrim\n---------------------------------------\n\nIn the examples above, `clickable` and `combinedClickable` add useful\nfunctionality to your composables. They show a visual indication on interaction,\nrespond to hovering, and include focus, keyboard, and accessibility support. But\nthis extra behavior is not always desirable.\n\nLet's look at the image detail screen. The background should be semi-transparent\nand the user should be able to tap that background to dismiss the detail screen:\n\nIn this case, that background should not have any visual indication on\ninteraction, should not respond to hovering, should not be focusable, and its\nresponse to keyboard and accessibility events differ from that of a typical\ncomposable. Instead of trying to adapt the `clickable` behavior, you can drop\ndown to a lower abstraction level and directly use the `pointerInput` modifier\nin combination with the `detectTapGestures` method:\n\n\n```kotlin\n@Composable\nprivate fun Scrim(onClose: () -\u003e Unit, modifier: Modifier = Modifier) {\n val strClose = stringResource(R.string.close)\n Box(\n modifier\n // handle pointer input\n .pointerInput(onClose) { detectTapGestures { onClose() } }\n // handle accessibility services\n .semantics(mergeDescendants = true) {\n contentDescription = strClose\n onClick {\n onClose()\n true\n }\n }\n // handle physical keyboard input\n .onKeyEvent {\n if (it.key == Key.Escape) {\n onClose()\n true\n } else {\n false\n }\n }\n // draw scrim\n .background(Color.DarkGray.copy(alpha = 0.75f))\n )\n}https://github.com/android/snippets/blob/dd30aee903e8c247786c064faab1a9ca8d10b46e/compose/snippets/src/main/java/com/example/compose/snippets/touchinput/pointerinput/TapAndPress.kt#L293-L322\n```\n\n\u003cbr /\u003e\n\nAs the key of the `pointerInput` modifier you pass the `onClose` lambda. This\nautomatically re-executes the lambda, making sure the right callback is called\nwhen the user taps the scrim.\n\nDouble tap to zoom\n------------------\n\nSometimes `clickable` and `combinedClickable` do not include enough information\nto respond to the interaction in the correct way. For example, composables might\nneed access to the position within the composable's bounds where the interaction\ntook place.\n\nLet's look at the image detail screen again. A best practice is to make it\npossible to zoom in on the image by double tapping:\n\nAs you can see in the video, zooming in occurs around the position of the tap\nevent. The result is different when we zoom in on the left part of the image\nversus the right part. We can use the `pointerInput` modifier in combination\nwith the `detectTapGestures` to incorporate the tap position into our\ncalculation:\n\n\n```kotlin\nvar zoomed by remember { mutableStateOf(false) }\nvar zoomOffset by remember { mutableStateOf(Offset.Zero) }\nImage(\n painter = rememberAsyncImagePainter(model = photo.highResUrl),\n contentDescription = null,\n modifier = modifier\n .pointerInput(Unit) {\n detectTapGestures(\n onDoubleTap = { tapOffset -\u003e\n zoomOffset = if (zoomed) Offset.Zero else\n calculateOffset(tapOffset, size)\n zoomed = !zoomed\n }\n )\n }\n .graphicsLayer {\n scaleX = if (zoomed) 2f else 1f\n scaleY = if (zoomed) 2f else 1f\n translationX = zoomOffset.x\n translationY = zoomOffset.y\n }\n)https://github.com/android/snippets/blob/dd30aee903e8c247786c064faab1a9ca8d10b46e/compose/snippets/src/main/java/com/example/compose/snippets/touchinput/pointerinput/TapAndPress.kt#L328-L351\n```\n\n\u003cbr /\u003e\n\nRecommended for you\n-------------------\n\n- Note: link text is displayed when JavaScript is off\n- [Understand gestures](/develop/ui/compose/touch-input/pointer-input/understand-gestures)\n- [Material Design 2 in Compose](/develop/ui/compose/designsystems/material)\n- [Kotlin for Jetpack Compose](/develop/ui/compose/kotlin)"]]