Appuyer et appuyer

De nombreux composables sont compatibles avec les appuis ou les clics, et incluent un Lambda onClick. Par exemple, vous pouvez créer un élément Surface cliquable qui inclut tous les comportements Material Design adaptés à l'interaction avec les surfaces:

Surface(onClick = { /* handle click */ }) {
    Text("Click me!", Modifier.padding(24.dp))
}

Mais les clics ne sont pas le seul moyen pour un utilisateur d'interagir avec les composables. Cette page se concentre sur les gestes impliquant un seul pointeur, où la position d'un ce pointeur n'est pas important pour le traitement de cet événement. Les éléments suivants : répertorie les types de gestes suivants:

Geste

Description

Appuyer (ou cliquer)

Le pointeur descend, puis vers le haut

Appuyez deux fois

Le pointeur descend, haut, bas, haut

Appuyer de manière prolongée

Le pointeur descend et est maintenu plus longtemps enfoncé

Presse

Le pointeur baisse

Répondre aux gestes d'appui ou de clic

clickable est un modificateur couramment utilisé qui permet à un composable de réagir à tapotements ou clics. Ce modificateur ajoute également des fonctionnalités supplémentaires, comme la prise en charge de le focus, le survol avec la souris et le stylet, et une indication visuelle personnalisable est maintenue enfoncée. Le modificateur répond aux "clics" au sens le plus large du terme, uniquement avec la souris ou le doigt, mais aussi pour les événements de clic via la saisie au clavier ou lorsque à l'aide de services d'accessibilité.

Imaginez une grille d'images, où une image s'affiche en plein écran lorsqu'un utilisateur clique dessus:

Vous pouvez ajouter le modificateur clickable à chaque élément de la grille pour implémenter cela. comportement:

@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 }
        )
    }
}

Le modificateur clickable ajoute également un comportement supplémentaire:

  • interactionSource et indication, qui dessinent une ondulation par défaut lorsqu'un appuie sur le composable. Découvrez comment les personnaliser dans la section Gérer les utilisateurs interactions.
  • Permet aux services d'accessibilité d'interagir avec l'élément en définissant des informations sémantiques.
  • Prise en charge des interactions avec le clavier ou le joystick en permettant la mise au point et en appuyant sur Enter ou le centre du pavé directionnel pour interagir.
  • Faites en sorte que l'élément puisse être survolé, afin qu'il réagisse au survol de la souris ou du stylet. dessus.

Appuyer de manière prolongée pour afficher un menu contextuel contextuel

combinedClickable vous permet d'ajouter le comportement de double appui ou d'appui de manière prolongée dans en plus des clics normaux. Vous pouvez utiliser combinedClickable pour afficher Menu contextuel lorsqu'un utilisateur touche de manière prolongée une image de grille:

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 }
    )
}

Nous vous recommandons d'inclure un retour haptique lorsque l'utilisateur appuie de manière prolongée sur les éléments. C'est pourquoi l'extrait inclut le Appel de performHapticFeedback.

Fermer un composable en appuyant sur un fond

Dans les exemples ci-dessus, clickable et combinedClickable ajoutent des éléments à vos composables. Ils montrent une indication visuelle de l'interaction, répondre aux survols et inclure le focus, le clavier et une prise en charge de l'accessibilité. Toutefois, ce comportement supplémentaire n'est pas toujours souhaitable.

Examinons l'écran des détails de l'image. L'arrière-plan doit être semi-transparent L'utilisateur doit pouvoir appuyer sur cet arrière-plan pour fermer l'écran d'informations:

Dans ce cas, cet arrière-plan ne doit avoir aucune indication visuelle sur ne doit pas répondre au passage de la souris, ne doit pas être sélectionnable, et son de réponse aux événements de clavier et d'accessibilité diffère de celle d'un composable. Au lieu d'essayer d'adapter le comportement de clickable, vous pouvez supprimer jusqu'à un niveau d'abstraction inférieur et utiliser directement le modificateur pointerInput en combinaison avec la méthode 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))
    )
}

En tant que clé du modificateur pointerInput, vous transmettez le lambda onClose. Ce réexécute automatiquement le lambda, en s'assurant que le rappel approprié est appelé lorsque l'utilisateur appuie sur le fond.

Appuyer deux fois pour zoomer

Parfois, clickable et combinedClickable n'incluent pas suffisamment d'informations de répondre à l’interaction de la bonne manière. Par exemple, les composables peuvent besoin d'accéder à la position dans les limites du composable où l'interaction s'est déroulée.

Regardons à nouveau l'écran des détails de l'image. Une bonne pratique consiste à rendre possibilité de faire un zoom avant sur l'image en appuyant deux fois:

Comme vous pouvez le voir dans la vidéo, un zoom avant se produit autour de l'endroit où . Le résultat est différent lorsque l'on fait un zoom avant sur la partie gauche de l'image par rapport à la bonne partie. Nous pouvons utiliser le modificateur pointerInput en combinaison avec detectTapGestures pour intégrer la position de l'appui dans notre calcul:

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
        }
)