多くのコンポーザブルにはタップやクリックのサポートが組み込まれており、
onClick
ラムダ。たとえば、クリック可能な Surface
を作成し、
には、サーフェスとのインタラクションに適したマテリアル デザインのすべての動作が含まれています。
Surface(onClick = { /* handle click */ }) { Text("Click me!", Modifier.padding(24.dp)) }
しかし、ユーザーがコンポーザブルを操作する方法はクリックだけではありません。このページ は、単一のポインタによる操作に焦点を当てています。 そのポインタは、そのイベントの処理には重要ではありません。次の 次の表に、操作の種類を示します。
ジェスチャー |
説明 |
タップ(またはクリック) |
ポインタが下から上に下がる |
ダブルタップ |
ポインタが下がる、上がる、上がる |
長押し |
ポインタが下がって、長時間保持される |
プレス |
ポインタが下がる |
タップまたはクリックに反応する
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
の動作を適応させる代わりに、
pointerInput
修飾子を直接使用する
detectTapGestures
メソッドと組み合わせると次のようになります。
@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 } )
あなたへのおすすめ
- 注: JavaScript がオフになっている場合はリンクテキストが表示されます
- ジェスチャーについて
- Compose のマテリアル デザイン 2
- Jetpack Compose で Kotlin を使用する