Wiele elementów kompozycyjnych ma wbudowaną obsługę kliknięć i kliknięć oraz zawiera lambda onClick
. Możesz na przykład utworzyć klikalny element Surface
, który będzie uwzględniał wszystkie zachowania stylu Material Design związane z interakcjami z powierzchniami:
Surface(onClick = { /* handle click */ }) { Text("Click me!", Modifier.padding(24.dp)) }
Jednak kliknięcia to nie jedyny sposób, w jaki użytkownik może wchodzić w interakcję z kompozycją. Ta strona dotyczy gestów obejmujących jeden wskaźnik, którego pozycja nie ma znaczenia dla obsługi danego zdarzenia. W tabeli poniżej znajdziesz listę tych typów gestów:
Gest |
Description |
Dotknij (lub kliknij) |
Wskaźnik maleje, a potem w górę |
Dwukrotne dotknięcie |
Wskaźnik maleje, w górę, w dół, w górę |
Długie naciśnięcie |
Wskaźnik maleje i jest utrzymywany przez dłuższy czas |
Prasa |
Wskaźnik maleje |
Reagowanie na kliknięcie
clickable
to powszechnie stosowany modyfikator, który sprawia, że funkcja kompozycyjna reaguje na kliknięcia. Ten modyfikator ma też dodatkowe funkcje, takie jak obsługa kursora myszy, najeżdżania kursorem myszy i rysikiem oraz dostosowywane wskaźniki wizualne po kliknięciu. Modyfikator reaguje na „kliknięcia” w najszerszym znaczeniu słowa – nie tylko myszką lub palcem, ale także zdarzeniami kliknięcia za pomocą klawiatury lub usług ułatwień dostępu.
Wyobraź sobie siatkę obrazów, w których obraz wyświetla się na pełnym ekranie, gdy użytkownik go kliknie:
Aby zastosować to działanie, do każdego elementu w siatce możesz dodać modyfikator 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 } ) } }
Modyfikator clickable
dodaje też dodatkowe działanie:
interactionSource
iindication
, które domyślnie rysują falę, gdy użytkownik kliknie element kompozycyjny. Na stronie Obsługa interakcji użytkowników dowiesz się, jak dostosować te parametry.- Umożliwia usługom ułatwień dostępu wchodzenie w interakcję z elementem przez ustawienie informacji semantycznych.
- Umożliwia interakcję z klawiaturą lub joystickiem przez naciśnięcie i przytrzymanie przycisku
Enter
lub środkowej części pada kierunkowego. - Zadbaj o to, aby element reagował na najeżdżanie na niego myszą lub rysikiem.
Przytrzymaj, aby wyświetlić menu kontekstowe
combinedClickable
umożliwia dodanie do normalnego działania polegającego na dwukrotnym kliknięciu lub przytrzymaniu przycisku. Korzystając z combinedClickable
, możesz wyświetlać menu kontekstowe, gdy użytkownik dotknie i przytrzyma obraz siatki:
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 reakcji na dotyk, gdy użytkownik przytrzyma i przytrzyma element. Dlatego fragment kodu zawiera wywołanie performHapticFeedback
.
Aby zamknąć kompozycję, kliknij ekran
W powyższych przykładach znaczniki clickable
i combinedClickable
dodają do elementów kompozycyjnych przydatne funkcje. Zawierają wizualne wskazówki dotyczące interakcji, reagują na najechanie kursorem, a także fokus, klawiaturę i ułatwienia dostępu. Jednak takie dodatkowe zachowanie
nie zawsze jest pożądane.
Przyjrzyjmy się ekranowi ze szczegółami obrazu. Tło powinno być półprzezroczyste, a użytkownik powinien mieć możliwość jego dotknięcia, by zamknąć ekran szczegółów:
W tym przypadku to tło nie powinno mieć żadnego wizualnego wskaźnika interakcji, nie powinno reagować na najechanie ani zaznaczyć, a jego reakcja na zdarzenia związane z klawiaturą i ułatwieniami dostępu różni się od typowej funkcji kompozycyjnej. Zamiast próbować dostosować działanie clickable
, możesz przejść na niższy poziom abstrakcji i bezpośrednio użyć modyfikatora pointerInput
w połączeniu z metodą 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)) ) }
Jako klucz modyfikatora pointerInput
przekazujesz lambda onClose
. Spowoduje to automatyczne ponowne wykonanie funkcji lambda, a po kliknięciu przez użytkownika nastąpi wywołanie odpowiedniego wywołania zwrotnego.
Kliknij dwukrotnie, aby powiększyć
Czasami clickable
i combinedClickable
zawierają za mało informacji, aby prawidłowo zareagować na interakcję. Na przykład kompozycje mogą wymagać dostępu do pozycji w granicach elementu kompozycyjnego, w której miała miejsce interakcja.
Ponownie przyjrzyjmy się ekranowi z informacjami o obrazie. Sprawdzoną metodą jest możliwość powiększenia obrazu przez dwukrotne kliknięcie:
Jak widać na filmie, powiększanie odbywa się w miejscu kliknięcia. Wynik wygląda inaczej, gdy powiększymy lewą część obrazu, a inną po prawej. Możemy użyć modyfikatora pointerInput
w połączeniu z elementem detectTapGestures
, aby w obliczeniach uwzględnić pozycję kliknięcia:
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 JavaScript jest wyłączony
- Gesty
- Material Design 2 w obszarze Utwórz
- Kotlin dla Jetpack Compose