Viele zusammensetzbare Funktionen haben eine integrierte Unterstützung für Tipp- oder Klickvorgänge und enthalten ein onClick
-Lambda. Du kannst beispielsweise ein anklickbares Surface
-Element erstellen, das alle Material Design-Verhaltensweisen umfasst, die für die Interaktion mit Oberflächen geeignet sind:
Surface(onClick = { /* handle click */ }) { Text("Click me!", Modifier.padding(24.dp)) }
Klicks sind jedoch nicht die einzige Möglichkeit, wie Nutzer mit zusammensetzbaren Funktionen interagieren können. Der Schwerpunkt dieser Seite liegt auf Gesten mit einem einzelnen Zeiger, bei denen die Position dieses Zeigers für die Verarbeitung des Ereignisses keine Rolle spielt. In der folgenden Tabelle sind diese Arten von Gesten aufgeführt:
Touch-Geste |
Beschreibung |
Tippen (oder klicken) |
Zeiger nach unten und dann nach oben |
Doppeltippen |
Zeiger nach unten, oben, unten, oben |
Lange drücken |
Zeiger nach unten und für längere Zeit gedrückt halten |
Drücken |
Zeiger nach unten |
Auf Tippen oder Klicken reagieren
clickable
ist ein häufig verwendeter Modifikator, der eine zusammensetzbare Funktion auf Tipp- oder Klickvorgänge ermöglicht. Mit diesem Modifikator werden zusätzliche Funktionen hinzugefügt, z. B. können der Fokus, die Maus und der Eingabestift bewegt werden und es gibt eine anpassbare visuelle Anzeige, wenn darauf geklickt wird. Der Modifikator reagiert auf „Klicks“ im weitesten Sinne des Wortes – nicht nur mit der Maus oder dem Finger, sondern auch auf Klickereignisse über Tastatureingaben oder bei Verwendung von Bedienungshilfen.
Stellen Sie sich ein Bildraster vor, in dem ein Bild im Vollbildmodus angezeigt wird, wenn ein Nutzer darauf klickt:
Sie können den clickable
-Modifikator jedem Element im Raster hinzufügen, um dieses Verhalten zu implementieren:
@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 } ) } }
Der clickable
-Modifikator fügt außerdem zusätzliches Verhalten hinzu:
interactionSource
undindication
, die standardmäßig eine Welle darstellen, wenn ein Nutzer auf die zusammensetzbare Funktion tippt. Auf der Seite Nutzerinteraktionen verarbeiten erfahren Sie, wie Sie diese anpassen können.- Ermöglicht es Bedienungshilfen, mit dem Element zu interagieren, indem die Semantikinformationen festgelegt werden.
- Unterstützt die Tastatur- oder Joystick-Interaktion durch fokussieren und Drücken von
Enter
oder der Mitte des Steuerkreuzes - Sie können das Element als Mouseover festlegen, damit es reagiert, wenn die Maus oder der Eingabestift darüber bewegt wird.
Lange drücken, um Kontextmenü einzublenden
Mit combinedClickable
können Sie zusätzlich zum normalen Klickverhalten das Doppeltippen oder langes Drücken verwenden. Mit combinedClickable
können Sie ein Kontextmenü anzeigen lassen, wenn ein Nutzer ein Rasterbild berührt und gedrückt hat:
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 } ) }
Als Best Practice sollten Sie haptisches Feedback einfügen, wenn der Nutzer lange auf Elemente drückt. Aus diesem Grund enthält das Snippet den Aufruf performHapticFeedback
.
Du kannst eine zusammensetzbare Funktion schließen, indem du auf ein Gitter tippst
In den obigen Beispielen bieten clickable
und combinedClickable
Ihren zusammensetzbaren Funktionen nützliche Funktionen. Sie zeigen die Interaktion visuell an, reagieren auf Bewegen des Mauszeigers und bieten Unterstützung für Fokus, Tastatur und Bedienungshilfen. Dieses zusätzliche Verhalten ist jedoch nicht immer wünschenswert.
Sehen wir uns den Bildschirm mit den Bilddetails an. Der Hintergrund sollte halbtransparent sein und der Nutzer sollte auf diesen Hintergrund tippen können, um den Detailbildschirm zu schließen:
In diesem Fall sollte der Hintergrund keine visuellen Hinweise auf die Interaktion haben, nicht auf Bewegen des Mauszeigers reagieren, nicht fokussierbar sein und seine Reaktion auf Tastatur- und Bedienungshilfen-Ereignisse unterscheidet sich von der einer typischen zusammensetzbaren Funktion. Anstatt zu versuchen, das Verhalten von clickable
anzupassen, können Sie auf eine niedrigere Abstraktionsebene klicken und den pointerInput
-Modifikator direkt in Kombination mit der Methode detectTapGestures
verwenden:
@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)) ) }
Als Schlüssel des pointerInput
-Modifikators übergibst du das Lambda onClose
. Dadurch wird das Lambda automatisch noch einmal ausgeführt, sodass der richtige Callback aufgerufen wird, wenn der Nutzer auf das Scrim tippt.
Zum Zoomen doppeltippen
Manchmal enthalten clickable
und combinedClickable
nicht genügend Informationen, um richtig auf die Interaktion zu reagieren. Beispielsweise benötigen zusammensetzbare Funktionen möglicherweise Zugriff auf die Position innerhalb der Grenzen der Funktion, an der die Interaktion stattgefunden hat.
Schauen wir uns noch einmal den Bildschirm mit den Bilddetails an. Es empfiehlt sich, das Bild durch Doppeltippen heranzuzoomen:
Wie Sie im Video sehen können, erfolgt das Heranzoomen um die Position des Tippereignisses. Das Ergebnis ist anders, wenn wir den linken und den rechten Teil des Bildes heranzoomen. Wir können den pointerInput
-Modifikator in Kombination mit detectTapGestures
verwenden, um die Tippposition in unsere Berechnung einzubeziehen:
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 } )
Empfehlungen für dich
- Hinweis: Der Linktext wird angezeigt, wenn JavaScript deaktiviert ist.
- Gesten und Bewegungen
- Material Design 2 in Compose
- Kotlin für Jetpack Compose