タップして押す

多くのコンポーザブルにはタップやクリックのサポートが組み込まれており、 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 修飾子を使用すると、次のような動作も追加されます。

  • interactionSourceindication: デフォルトでは、 ユーザーがコンポーザブルをタップします。これらをカスタマイズする方法については、ユーザーの処理に関するページ できます。
  • 次のように設定することで、ユーザー補助サービスが要素とやり取りできるようにします。 意味情報を提供します。
  • フォーカスと押下によるキーボードまたはジョイスティックの操作をサポート 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 の呼び出し。

スクリムをタップしてコンポーザブルを閉じる

上記の例では、clickablecombinedClickable が有用な 追加しましょう。操作が視覚的に示され マウスオーバーに応答し、フォーカス、キーボード、ユーザー補助のサポートを含めます。しかし、 この余分な動作は、常に望ましいとは限りません。

画像の詳細画面を見てみましょう。背景は半透明にする ユーザーがその背景をタップして詳細画面を閉じることができるようにする必要があります。

この場合、その背景は表示されなくなります。 マウスオーバーに反応しない、フォーカス可能でなく、 キーボードやユーザー補助イベントへの応答が、一般的な 作成します。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 ラムダを渡します。この 自動的にラムダを再実行し、適切なコールバックが呼び出されるようにします。 ユーザーがスクリムをタップしたときに表示されます。

ダブルタップで拡大

clickablecombinedClickable には十分な情報が含まれていない場合があります 適切な方法で対応する必要があります。たとえばコンポーザブルは 操作が行われる場合、コンポーザブルの境界内の位置にアクセスする必要があります。 行ったことになります。

もう一度画像詳細画面を見てみましょう。ベスト プラクティスは、 ダブルタップで画像を拡大できます。

動画からわかるように、タップした位置の付近でズームインが発生します。 イベントです。画像の左側にズームインすると、結果は異なります 見ていきましょう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
        }
)