Wprowadzanie obrotowe z funkcją tworzenia

Obrotowe dane wejściowe zegarka to dane wejściowe wirujące lub obracające się. Zazwyczaj użytkownicy poświęcają tylko kilka sekund na interakcję z zegarkiem. Możesz zwiększyć wygodę użytkowników, stosując rotacyjne dane wejściowe, aby umożliwić im szybkie wykonywanie różnych zadań.

Trzy główne źródła sygnału obrotowego większości zegarków to obrotowy przycisk boczny (RSB) oraz fizyczna ramka lub dotykowa ramka, która stanowi okrągłą strefę dotykową wokół ekranu. Choć oczekiwane działanie może się różnić w zależności od typu danych wejściowych, pamiętaj, aby włączyć pokrętło do wszystkich niezbędnych interakcji.

Przewiń

Większość użytkowników oczekuje, że aplikacje będą obsługiwać gest przewijania. Gdy treść przewija się na ekranie, zapewnij użytkownikowi wizualną reakcję na interakcje z pokrętłem. Sygnały wizualne mogą obejmować wskaźniki pozycji w przypadku przewijania w pionie lub wskaźniki strony.

Na Wear OS zaimplementuj przewijanie obrotowe za pomocą funkcji Utwórz. Ten przykład opisuje aplikację ze scaffold i elementem ScalingLazyColumn, który można przewijać w pionie. Scaffold zapewnia podstawową strukturę układu dla aplikacji na Wear OS i ma już miejsce na wskaźnik przewijania. Aby pokazać postęp przewijania, utwórz wskaźnik pozycji oparty na obiekcie stanu listy. Widoki przewijane, w tym ScalingLazyColumn, można już przewijać, aby dodać pokrętło. Aby otrzymywać zdarzenia przewijania obrotowego, wykonaj te czynności:

  1. Wyraźnie zażądaj zaznaczenia za pomocą funkcji FocusRequester.
  2. Dodaj modyfikator onRotaryScrollEvent, aby przechwytywać zdarzenia generowane przez system, gdy użytkownik obraca pokrętło lub obraca ramkę. Każde zdarzenie obrotowe ma ustaloną wartość w pikselach i przewija się w pionie lub w poziomie. Modyfikator zawiera też wywołanie zwrotne wskazujące, czy zdarzenie zostało przetworzone, i po użyciu zatrzymuje propagację zdarzenia do elementów nadrzędnych.
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(),
        state = listState
    ) { ... }
}

Wartości dyskretne

Za pomocą pokrętła możesz też dostosować wartości dyskretne, np. dostosować jasność w ustawieniach lub wybrać liczby w selektorze godziny przy ustawianiu alarmu.

Podobnie jak w przypadku aplikacji ScalingLazyColumn, selektor, suwak, kreator krokowy i inne elementy kompozycyjne muszą być zaznaczone, aby otrzymywać pokrętła. Jeśli na ekranie jest wyświetlanych wiele przewijanych celów, np. godziny i minuty w selektorze czasu, utwórz element FocusRequester dla każdego celu i ułatw obecny wybór pola, gdy użytkownik kliknie godzinę lub minuty.

@Composable
fun TimePicker() {
    var selectedColumn by remember { mutableStateOf(0) }
    val focusRequester1 = remember { FocusRequester() }
    val focusRequester2 = remember { FocusRequester() }

    Row {
       Picker(...)
       Picker(...)
    }

    LaunchedEffect(selectedColumn) {
        listOf(focusRequester1,
               focusRequester2)[selectedColumn]
            .requestFocus()
    }
}

Działania niestandardowe

Możesz też tworzyć niestandardowe działania, które reagują na pokrętło używane w aplikacji. Możesz na przykład używać pokrętła do powiększania i pomniejszania lub do sterowania głośnością w aplikacji do multimediów.

Jeśli komponent natywnie nie obsługuje zdarzeń przewijania, takich jak regulacja głośności, możesz je obsługiwać samodzielnie.

// VolumeScreen.kt

val focusRequester: FocusRequester = remember { FocusRequester() }

Column(
    modifier = Modifier
        .fillMaxSize()
        .onRotaryScrollEvent {
            // handle rotary scroll events
            true
        }
        .focusRequester(focusRequester)
        .focusable(),
) { ... }

Utwórz niestandardowy stan zarządzany w modelu widoku danych i niestandardowe wywołanie zwrotne używane do przetwarzania zdarzeń przewijania obrotowego.

// 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)
    }
}

Dla uproszczenia w poprzednim przykładzie użyto wartości pikseli, które w przypadku rzeczywistego użycia mogą być zbyt czułe.

Skorzystaj z wywołania zwrotnego po otrzymaniu zdarzeń, tak jak w tym fragmencie.

val focusRequester: FocusRequester = remember { FocusRequester() }
val volumeState by volumeViewModel.volumeState.collectAsState()

Column(
    modifier = Modifier
        .fillMaxSize()
        .onRotaryScrollEvent {
            volumeViewModel
                .onVolumeChangeByScroll(it.verticalScrollPixels)
            true
        }
        .focusRequester(focusRequester)
        .focusable(),
) { ... }

Dodatkowe materiały

Rozważ skorzystanie z Horologist – projektu Google typu open source, który udostępnia zestaw bibliotek Wear OS uzupełniający funkcje Compose na Wear OS i inne interfejsy API Wear OS. Horologist zajmuje się wdrażaniem zaawansowanych przypadków użycia i wieloma szczegółami dotyczącymi konkretnych urządzeń.

Na przykład czułość różnych pokrętła źródeł sygnału może być inna. Aby płynniej przechodzić między wartościami, możesz ograniczyć liczbę żądań lub dodać przyciąganie lub animacje do przejść. Dzięki temu obracanie urządzenia wydaje się bardziej naturalne. Horolog uwzględnia modyfikatory komponentów możliwych do przewijania i wartości dyskretnych. Zawiera też narzędzia do obsługi skupienia i bibliotekę interfejsu audio do implementacji sterowania głośnością za pomocą reakcji haptycznych.

Więcej informacji znajdziesz w sekcji Horolog na GitHubie.