Muitos elementos combináveis têm suporte integrado a toques ou cliques e incluem um
Lambda onClick
. Por exemplo, é possível criar um Surface
clicável que
inclui todo o comportamento do Material Design apropriado para a interação com superfícies:
Surface(onClick = { /* handle click */ }) { Text("Click me!", Modifier.padding(24.dp)) }
No entanto, cliques não são a única maneira de interagir com elementos combináveis. Esta página concentra-se em gestos que envolvem um único ponteiro, em que a posição esse ponteiro não é significativo para o tratamento desse evento. O seguinte lista estes tipos de gestos:
Gesto |
Descrição |
Toque (ou clique) |
O ponteiro cai e depois para cima |
Tocar duas vezes |
O ponteiro vai para baixo, para cima, para baixo, para cima |
Manter pressionado |
O ponteiro cai e é mantido por mais tempo |
Imprensa |
O ponteiro aperta |
Responder a um toque ou clique
clickable
é um modificador usado com frequência que faz um elemento combinável reagir a
toques ou cliques. Esse modificador também adiciona outros recursos, como suporte a
foco, passagem do mouse e da stylus e uma indicação visual personalizável quando
pressionado. O modificador responde a "cliques", no sentido mais amplo da palavra, não
somente com o mouse ou dedo, mas também em eventos de clique por meio da entrada do teclado ou quando
usar serviços de acessibilidade.
Imagine uma grade de imagens, em que uma imagem aparece em tela cheia quando um usuário clicar nele:
Você pode adicionar o modificador clickable
a cada item na grade para implementar essa
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 } ) } }
O modificador clickable
também adiciona outros comportamentos:
interactionSource
eindication
, que desenham uma ondulação por padrão quando uma o usuário toca no elemento combinável. Aprenda a personalizá-los no artigo Como lidar com o de interações.- Permite que os serviços de acessibilidade interajam com o elemento configurando o informações semânticas.
- Oferece suporte à interação com teclado ou joystick ao permitir foco e pressionar
Enter
ou o centro do botão direcional para interagir. - Tornar o elemento passível de passagem de cursor para que ele responda ao cursor do mouse ou da stylus sobre ele.
Toque e mantenha pressionado para mostrar um menu de contexto
O combinedClickable
permite adicionar o comportamento de tocar duas vezes ou tocar e manter pressionado
além do comportamento de clique normal. Você pode usar combinedClickable
para mostrar
no menu de contexto quando um usuário toca e mantém uma imagem de grade:
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 } ) }
Como prática recomendada, você deve incluir o retorno tátil quando o usuário
toca e mantém os elementos pressionados, e é por isso que o snippet inclui o
Invocação performHapticFeedback
.
Dispensar um elemento combinável tocando em um scrim
Nos exemplos acima, clickable
e combinedClickable
adicionam valores úteis
aos elementos combináveis. Eles mostram uma indicação visual sobre a interação,
respondem ao movimento do cursor e incluem foco, teclado e suporte à acessibilidade. Mas
esse comportamento extra nem sempre é desejável.
Vamos analisar a tela de detalhes da imagem. O plano de fundo precisa ser semitransparente e o usuário poderá tocar nesse plano de fundo para dispensar a tela de detalhes:
Nesse caso, esse fundo não deve ter nenhuma indicação visual sobre
de entrada, não deve responder ao passar o cursor, não deve ser focalizável e sua
resposta a eventos de teclado e acessibilidade diferente de uma resposta
combinável. Em vez de tentar adaptar o comportamento da clickable
, você pode soltar
para um nível de abstração inferior e usar diretamente o modificador pointerInput
em combinação com o método 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)) ) }
Como a chave do modificador pointerInput
, transmita a lambda onClose
. Isso
executa novamente a lambda de maneira automática, garantindo que o callback certo seja chamado.
quando o usuário toca no scrim.
Toque duas vezes para ampliar
Às vezes, clickable
e combinedClickable
não incluem informações suficientes
de responder à interação da maneira correta. Por exemplo, os elementos combináveis podem
precisam de acesso à posição dentro dos limites do elemento combinável em que a interação
o incidente.
Vamos analisar novamente a tela de detalhes da imagem. Uma prática recomendada é torná-la possível aumentar o zoom na imagem tocando duas vezes:
Como você pode ver no vídeo, o zoom ocorre próximo à posição do toque
evento. O resultado é diferente quando aumentamos o zoom na parte esquerda da imagem
em vez da parte certa. Podemos usar o modificador pointerInput
em combinação
com o detectTapGestures
para incorporar a posição de toque à nossa
cálculo:
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 } )
Recomendados para você
- Observação: o texto do link aparece quando o JavaScript está desativado.
- Entender os gestos
- Material Design 2 no Compose
- Kotlin para Jetpack Compose