O termo "entrada por seletor giratório" se refere a ações feitas usando peças do relógio que giram. Em média, os usuários passam apenas alguns segundos interagindo com o relógio. É possível melhorar a experiência usando a entrada por seletor giratório para que os usuários possam realizar várias tarefas rapidamente.
As três principais fontes de entrada por seletor giratório na maioria dos relógios incluem o botão lateral giratório (RSB, na sigla em inglês) e uma borda física ou sensível ao toque, que é uma zona de toque circular ao redor da tela. Embora o comportamento esperado possa variar de acordo com o tipo de entrada, recomendamos que você ofereça suporte à entrada por seletor giratório para todas as interações essenciais.
Rolagem
A maioria dos usuários espera que os apps tenham suporte ao gesto de rolagem. À medida que o conteúdo passa pela tela, ofereça feedback visual aos usuários em resposta a interações pelo seletor giratório. O feedback visual pode incluir indicadores de posição para rolagem vertical ou indicadores de página.
Implemente a rolagem por seletor giratório usando o Compose para Wear OS. Este exemplo
descreve um app com um scaffold e uma função ScalingLazyColumn
com
rolagem vertical. O scaffold fornece a estrutura de layout básica
usada em apps para Wear OS e já tem um slot para um indicador de rolagem. Para
mostrar o progresso da rolagem, crie um indicador de posição com base no objeto de estado da lista. As visualizações roláveis, incluindo ScalingLazyColumn
,
já têm um estado rolável para adicionar a entrada por seletor giratório. Para receber
eventos de rolagem por seletor giratório, faça o seguinte:
Solicite o foco explicitamente usando
FocusRequester
. UsarHierarchicalFocusCoordinator
para casos mais complexos, como vários ObjetosScalingLazyColumns
em umaHorizontalPager
.Adicione o modificador
onRotaryScrollEvent
para interceptar eventos que o sistema gera quando um usuário gira a coroa ou a borda. Cada evento giratório tem a definição de um valor de pixel e de uma rolagem vertical ou horizontal. O modificador também tem um callback para indicar se o evento é consumido e, em caso positivo, interrompe a propagação de eventos para os pais.
val listState = rememberScalingLazyListState() Scaffold( positionIndicator = { PositionIndicator(scalingLazyListState = listState) } ) { val focusRequester = rememberActiveFocusRequester() val coroutineScope = rememberCoroutineScope() ScalingLazyColumn( modifier = Modifier .onRotaryScrollEvent { coroutineScope.launch { listState.scrollBy(it.verticalScrollPixels) listState.animateScrollBy(0f) } true } .focusRequester(focusRequester) .focusable() .fillMaxSize(), state = listState ) { // Content goes here // ... } }
Valores discretos
Use também interações giratórias para ajustar valores discretos, como mudar o brilho nas configurações ou selecionar os números no seletor de horário ao definir um alarme.
Assim como ScalingLazyColumn
, o seletor, o controle deslizante, o stepper e outros elementos combináveis
precisam de foco para receber a entrada por seletor giratório. No caso de vários destinos
roláveis na tela, como as horas e os minutos no seletor de horário, você precisará criar
um FocusRequester
para cada destino e processar a mudança de foco conforme necessário quando o
usuário tocar nas horas ou nos minutos.
var selectedColumn by remember { mutableIntStateOf(0) } val hoursFocusRequester = remember { FocusRequester() } val minutesRequester = remember { FocusRequester() } // ... Scaffold(modifier = Modifier.fillMaxSize()) { Row( // ... // ... ) { // ... Picker( readOnly = selectedColumn != 0, modifier = Modifier.size(64.dp, 100.dp) .onRotaryScrollEvent { coroutineScope.launch { hourState.scrollBy(it.verticalScrollPixels) } true } .focusRequester(hoursFocusRequester) .focusable(), onSelected = { selectedColumn = 0 }, // ... // ... ) // ... Picker( readOnly = selectedColumn != 1, modifier = Modifier.size(64.dp, 100.dp) .onRotaryScrollEvent { coroutineScope.launch { minuteState.scrollBy(it.verticalScrollPixels) } true } .focusRequester(minutesRequester) .focusable(), onSelected = { selectedColumn = 1 }, // ... // ... ) LaunchedEffect(selectedColumn) { listOf( hoursFocusRequester, minutesRequester )[selectedColumn] .requestFocus() } } }
Ações personalizadas
Também é possível criar ações personalizadas que respondam à entrada por seletor giratório no app. Por exemplo, use a entrada por seletor giratório para aumentar e diminuir o zoom ou controlar o volume em um app de música.
Se o componente não tiver suporte nativo a eventos de rolagem, como o controle de volume, você poderá processar esses eventos por conta própria.
// VolumeScreen.kt
val focusRequester: FocusRequester = remember { FocusRequester() }
Column(
modifier = Modifier
.fillMaxSize()
.onRotaryScrollEvent {
// handle rotary scroll events
true
}
.focusRequester(focusRequester)
.focusable(),
) { ... }
Crie um estado personalizado gerenciado no modelo de visualização e um callback individualizado que seja usado para processar eventos de rolagem por seletor giratório.
// VolumeViewModel.kt
object VolumeRange(
public val max: Int = 10
public val min: Int = 0
)
val volumeState: MutableStateFlow<Int> = ...
fun onVolumeChangeByScroll(pixels: Float) {
volumeState.value = when {
pixels > 0 -> min (volumeState.value + 1, VolumeRange.max)
pixels < 0 -> max (volumeState.value - 1, VolumeRange.min)
}
}
Para simplificar, o exemplo anterior usa valores de pixel que, se usados de fato, serão muito sensíveis.
Use o callback quando receber os eventos, conforme mostrado no snippet a seguir.
val focusRequester: FocusRequester = remember { FocusRequester() }
val volumeState by volumeViewModel.volumeState.collectAsState()
Column(
modifier = Modifier
.fillMaxSize()
.onRotaryScrollEvent {
volumeViewModel
.onVolumeChangeByScroll(it.verticalScrollPixels)
true
}
.focusRequester(focusRequester)
.focusable(),
) { ... }
Outros recursos
Considere usar o Horologist, um projeto de código aberto do Google que disponibiliza um conjunto de bibliotecas do Wear que complementam a funcionalidade do Compose para Wear OS e outras APIs do Wear OS. O Horologist fornece uma implementação para casos de uso avançados e vários detalhes específicos dos dispositivos.
Por exemplo, a sensibilidade de diferentes origens de entrada por seletor giratório pode variar. Para que a transição seja mais suave entre os valores, é possível usar a limitação de taxa ou adicionar ajustes ou animações. Isso deixa a velocidade mais natural para os usuários. O Horologist inclui modificadores para componentes roláveis e para valores discretos. Ele também inclui utilitários para processar o foco e uma biblioteca de interfaces de áudio para implementar o controle de volume com retorno tátil.
Para mais informações, consulte o Horologist (link em inglês) no GitHub.
Recomendados para você
- Observação: o texto do link aparece quando o JavaScript está desativado.
- Mudar o comportamento de foco
- Adicionar suporte para teclado, mouse, trackpad e stylus com o Jetpack Compose
- Codelab sobre o Compose para Wear OS