Molti componibili hanno un supporto integrato per tocchi o clic e includono una funzione lambda onClick
. Ad esempio, puoi creare un elemento Surface
cliccabile che includa tutti i comportamenti di Material Design appropriati per l'interazione con le piattaforme:
Surface(onClick = { /* handle click */ }) { Text("Click me!", Modifier.padding(24.dp)) }
Tuttavia, i clic non sono l'unico modo in cui un utente può interagire con i componibili. Questa pagina è incentrata sui gesti che prevedono un singolo puntatore, in cui la posizione del puntatore non è significativa per la gestione dell'evento. Nella tabella che segue sono elencati questi tipi di gesti:
Gesto |
Descrizione |
Toccare (o fare clic) |
Il puntatore scende e poi verso l'alto |
Toccare due volte |
Il puntatore del mouse va in basso, in alto, in basso, in alto |
Pressione lunga |
Il puntatore diminuisce e viene tenuto per più tempo |
Interviste |
Puntatore abbassato |
Rispondere al tocco o al clic
clickable
è un modificatore di uso comune che genera una reazione componibile a
tocchi o clic. Questo modificatore aggiunge anche funzionalità aggiuntive, come il supporto per lo stato attivo, il passaggio del mouse e dello stilo e un'indicazione visiva personalizzabile al tocco. Il modificatore risponde ai "clic" nel senso più ampio del termine, non solo con il mouse o il dito, ma anche con i clic tramite l'input da tastiera o quando
si utilizzano i servizi di accessibilità.
Immagina una griglia di immagini, in cui un'immagine viene visualizzata a schermo intero quando un utente fa clic su di essa:
Puoi aggiungere il modificatore clickable
a ogni elemento della griglia per implementare questo
comportamento:
@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 } ) } }
Il modificatore clickable
aggiunge anche un comportamento aggiuntivo:
interactionSource
eindication
, che tracciano un'onda per impostazione predefinita quando un utente tocca il componibile. Scopri come personalizzarle nella pagina Gestione delle interazioni utente.- Consente ai servizi di accessibilità di interagire con l'elemento impostando le informazioni sulla semantica.
- Supporta l'interazione con la tastiera o il joystick consentendo lo stato attivo e premendo
Enter
o il centro del D-pad per interagire. - Passa il mouse sopra l'elemento in modo che risponda al passaggio del mouse o dello stilo.
Tieni premuto per visualizzare un menu contestuale contestuale
combinedClickable
ti consente di aggiungere il comportamento del doppio tocco o della pressione prolungata oltre al normale comportamento del clic. Puoi usare combinedClickable
per mostrare un menu contestuale quando un utente tocca e tiene premuta un'immagine della griglia:
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 } ) }
Come best practice, dovresti includere il feedback aptico quando l'utente
preme a lungo gli elementi, motivo per cui lo snippet include la
chiamata a performHapticFeedback
.
Ignorare un componibile toccando una tela
Negli esempi precedenti, clickable
e combinedClickable
aggiungono
funzionalità utili ai tuoi componibili. Mostrano indicazioni visive sull'interazione,
rispondono al passaggio del mouse e includono lo stato attivo, la tastiera e il supporto per l'accessibilità. Tuttavia, questo comportamento aggiuntivo non è sempre auspicabile.
Diamo un'occhiata alla schermata dei dettagli dell'immagine. Lo sfondo deve essere semitrasparente e l'utente deve essere in grado di toccarlo per chiudere la schermata dei dettagli:
In questo caso, lo sfondo non deve avere indicazioni visive sull'interazione, non deve rispondere al passaggio del mouse e non deve essere attivabile e la sua risposta agli eventi di tastiera e di accessibilità è diversa da quella di un tipico componibile. Anziché provare ad adattare il comportamento di clickable
, puoi impostare un menu a discesa a un livello di astrazione inferiore e utilizzare direttamente il modificatore pointerInput
in combinazione con il metodo detectTapGestures
:
@OptIn(ExperimentalComposeUiApi::class) @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)) ) }
Come tasto del modificatore pointerInput
passi la lambda onClose
. Questo
riesegui automaticamente il lambda, assicurandosi che venga richiamato il callback corretto
quando l'utente tocca lo scrim.
Tocca due volte per eseguire lo zoom
A volte clickable
e combinedClickable
non includono informazioni sufficienti
per rispondere all'interazione nel modo corretto. Ad esempio, gli elementi componibili potrebbero
richiedere l'accesso alla posizione entro i relativi limiti in cui si è verificata l'interazione.
Diamo di nuovo un'occhiata alla schermata dei dettagli dell'immagine. Una best practice consiste nel consentire di aumentare lo zoom sull'immagine toccando due volte:
Come puoi vedere nel video, viene aumentato lo zoom intorno alla posizione dell'evento tocco. Il risultato è diverso quando aumentiamo lo zoom sulla parte sinistra
dell'immagine e su quella destra. Possiamo utilizzare il modificatore pointerInput
in combinazione
con detectTapGestures
per incorporare la posizione del tocco nel
calcolo:
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 } )
Consigliato per te
- Nota: il testo del link viene visualizzato quando JavaScript è disattivato
- Informazioni sui gesti
- Material Design 2 in Compose
- Kotlin per Jetpack Compose