Wiele komponentów ma wbudowane funkcje obsługi dotyku lub kliknięcia i obsługuje funkcję onClick
lambda. Możesz na przykład utworzyć klikalny element Surface
, który będzie uwzględniał wszystkie zachowania związane z Material Design odpowiednie do interakcji z powierzchniami:
Surface(onClick = { /* handle click */ }) { Text("Click me!", Modifier.padding(24.dp)) }
Jednak kliknięcia nie są jedynym sposobem na interakcję z komponowanymi usługami. Ta strona skupia się na gestach, które wykorzystują jeden wskaźnik, a jego pozycja nie ma znaczenia dla obsługi danego zdarzenia. W tabeli poniżej znajdziesz te typy gestów:
Gest |
Opis |
Dotknij (lub kliknij) |
Wskaźnik przesuwa się w dół, a potem w górę |
Dwukrotne dotknięcie |
Wskaźnik przesuwa się w dół, w górę, w dół i w górę |
Długie naciśnięcie |
Wskaźnik schodzi w dół i zostaje w tym położeniu przez dłuższy czas |
Prasa |
Wskaźnik schodzi w dół |
Odpowiedź na dotknięcie lub kliknięcie
clickable
to często używany modyfikator, który sprawia, że komponent reaguje na dotknięcia lub kliknięcia. Ten modyfikator dodaje też dodatkowe funkcje, takie jak obsługa fokusa, podświetlenie myszy i rysika oraz możliwość dostosowania wizualnego wskazania po naciśnięciu. Modyfikator reaguje na „kliknięcia” w najszerszym tego słowa znaczeniu – nie tylko za pomocą myszy lub palca, ale też zdarzeń kliknięcia za pomocą klawiatury lub podczas korzystania z usług ułatwień dostępu.
Wyobraź sobie siatkę obrazów, w której po kliknięciu obraz wyświetla się na pełnym ekranie:
Aby wdrożyć to zachowanie, możesz dodać modyfikator clickable
do każdego elementu w kratce:
@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 } ) } }
Modyfikator clickable
wprowadza też dodatkowe działanie:
interactionSource
iindication
, które domyślnie wyświetlają efekt falowania, gdy użytkownik kliknie element kompozytywny. Dowiedz się, jak je dostosowywać na stronie Zarządzanie interakcjami z użytkownikami.- Umożliwia usługom ułatwień dostępu interakcję z elementem przez ustawienie informacji semantycznych.
- Obsługuje interakcje za pomocą klawiatury lub joysticka, umożliwiając skupienie się na środku pada i naciśnięcie przycisku
Enter
. - Ustaw element tak, aby można było go podświetlić kursorem myszy lub rysika.
Przytrzymaj, aby wyświetlić menu kontekstowe
combinedClickable
pozwala dodać działanie dwukrotnego kliknięcia lub długiego naciśnięcia oprócz normalnego kliknięcia. Gdy użytkownik dotknie i przytrzyma obraz siatki, możesz użyć combinedClickable
, aby wyświetlić menu kontekstowe:
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 } ) }
Sprawdzoną metodą jest uwzględnianie informacji zwrotnej haptycznej, gdy użytkownik naciska elementy przez dłuższy czas, dlatego fragment kodu zawiera wywołanie performHapticFeedback
.
Zamknij kompozyt, klikając ekran zasłaniający
W powyższych przykładach komponenty clickable
i combinedClickable
dodają przydatne funkcje do komponentów składanych. Wyświetlają wizualne wskazanie interakcji, reagują na najechanie kursorem, obsługują fokus, klawiaturę i ułatwienia dostępu. Jednak takie dodatkowe działanie nie zawsze jest pożądane.
Przyjrzyjmy się ekranowi z informacjami o obrazie. Tło powinno być półprzezroczyste, a użytkownik powinien mieć możliwość kliknięcia tego tła, aby zamknąć ekran z informacjami:
W tym przypadku tło nie powinno zawierać żadnych wizualnych wskazówek dotyczących interakcji, nie powinno reagować na najechanie kursorem, nie powinno być możliwe do skoncentrowania, a jego reakcja na zdarzenia związane z klawiaturą i dostępnością powinna różnić się od reakcji typowego komponentu. Zamiast próbować dostosować zachowanie clickable
, możesz przejść na niższy poziom abstrakcji i bezpośrednio użyć modyfikatora pointerInput
w połączeniu z metodą 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)) ) }
Jako klucz modyfikatora pointerInput
przekazujesz lambda onClose
. Ta funkcja automatycznie ponownie wykonuje funkcję lambda, aby upewnić się, że odpowiednia funkcja wywołania zwrotnego zostanie wywołana, gdy użytkownik kliknie ekran.
Kliknij dwukrotnie, aby powiększyć
Czasami clickable
i combinedClickable
nie zawierają wystarczającej ilości informacji, aby prawidłowo zareagować na interakcję. Na przykład komponenty mogą potrzebować dostępu do pozycji w ograniczeniach komponentu, w której miała miejsce interakcja.
Przyjrzyjmy się jeszcze raz ekranowi z informacjami o obrazie. Sprawdzoną metodą jest umożliwienie powiększania obrazu przez dwukrotne kliknięcie:
Jak widać na filmie, powiększanie następuje wokół pozycji zdarzenia dotknięcia. Wynik jest inny, gdy przybliżymy lewą część obrazu w porównaniu z prawą. Aby uwzględnić pozycję kliknięcia w obliczeniach, możemy użyć modyfikatora pointerInput
w połączeniu z wartością 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 } )
Polecane dla Ciebie
- Uwaga: tekst linku jest wyświetlany, gdy obsługa JavaScript jest wyłączona
- Informacje o gestach
- Material Design 2 w Compose
- Kotlin w Jetpack Compose