Dodawanie obsługi animacji przewidywanego przejścia wstecz w widokach

Za pomocą widoków lub Compose możesz tworzyć niestandardowe animacje i przejścia właściwości w aplikacji, niestandardowe animacje między aktywnościami oraz niestandardowe animacje między fragmentami z użyciem gestów przewidywanego przejścia wstecz. Aby wypróbować sposób Compose, zobacz Dodawanie obsługi animacji przewidywanego przejścia wstecz.

Dodawanie niestandardowych przejść za pomocą interfejsu Progress API

W AndroidzieX Activity 1.8.0-alpha01 lub nowszym możesz używać interfejsów Predictive Back Progress API do tworzenia niestandardowych animacji dla gestu przewidywanego przejścia wstecz w aplikacji. Interfejsy Progress API są przydatne do animowania widoków, ale mają ograniczenia w przypadku animowania przejść między fragmentami. W OnBackPressedCallback wprowadziliśmy metody handleOnBackProgressed, handleOnBackCancelled i handleOnBackStarted, aby animować obiekty, gdy użytkownik przesuwa palcem wstecz. Użyj tych metod, jeśli chcesz dostosować więcej niż domyślne animacje dostarczane przez system lub animacje komponentu Material.

Oczekujemy, że większość aplikacji będzie korzystać z interfejsów AndroidX API, które są zgodne wstecz, ale są też podobne interfejsy Platform API w obrębie OnBackAnimationCallback interfejsu, które można testować w Androidzie 14 i nowszym.

Używanie interfejsów Progress API z przejściami AndroidX

Interfejsy Progress API można używać z przejściami AndroidX 1.5.0-alpha01 lub nowszymi w Androidzie 14 i nowszym do tworzenia przejść przewidywanego przejścia wstecz.

  1. Zamiast beginDelayedTransition użyj TransitionManager#controlDelayedTransition, aby odtwarzać przejścia, gdy użytkownik przesuwa palcem wstecz.
  2. Utwórz przejście w handleOnBackStarted.
  3. Odtwórz przejście za pomocą zdarzenia wstecz w handleOnBackProgressed, łącząc currentFraction z BackEvent.progress, które pokazuje, jak daleko użytkownik przesunął palcem wstecz.
  4. Zakończ przejście po tym, jak użytkownik wykona gest przejścia wstecz w handleOnBackPressed.
  5. Na koniec zresetuj stan przejścia w handleOnBackCancelled.

Poniższy film, kod Kotlin i kod XML pokazują niestandardowe przejście między 2 polami zaimplementowane za pomocą OnBackPressedCallback:

    class MyFragment : Fragment() {

    val transitionSet = TransitionSet().apply {
        addTransition(Fade(Fade.MODE_OUT))
        addTransition(ChangeBounds())
        addTransition(Fade(Fade.MODE_IN))
    }
    ...
    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)

        val callback = object : OnBackPressedCallback(enabled = false) {

            var controller: TransitionSeekController? = null

            @RequiresApi(34)
            override fun handleOnBackStarted(backEvent: BackEvent) {
                // Create the transition
                controller = TransitionManager.controlDelayedTransition(
                    binding.card,
                    transitionSet
                )
                changeTextVisibility(ShowText.SHORT)
            }

            @RequiresApi(34)
            override fun handleOnBackProgressed(backEvent: BackEvent) {
                // Play the transition as the user swipes back
                if (controller?.isReady == true) {
                    controller?.currentFraction = backEvent.progress
                }
            }

            override fun handleOnBackPressed() {
                // Finish playing the transition when the user commits back
                controller?.animateToEnd()
                this.isEnabled = false
            }

            @RequiresApi(34)
            override fun handleOnBackCancelled() {
                // If the user cancels the back gesture, reset the state
                transition(ShowText.LONG)
            }
        }

        binding.shortText.setOnClickListener {
            transition(ShowText.LONG)
            callback.isEnabled = true
        }

        this.requireActivity().onBackPressedDispatcher.addCallback(callback)
    }

    private fun transition(showText: ShowText) {
        TransitionManager.beginDelayedTransition(
            binding.card,
            transitionSet
        )
        changeTextVisibility(showText)
    }

    enum class ShowText { SHORT, LONG }
    private fun changeTextVisibility(showText: ShowText) {
        when (showText) {
            ShowText.SHORT -> {
                binding.shortText.isVisible = true
                binding.longText.isVisible = false
            }
            ShowText.LONG -> {
                binding.shortText.isVisible = false
                binding.longText.isVisible = true
            }
        }
    }
}
  
<?xml version="1.0" encoding="utf-8"?>
...
    <androidx.constraintlayout.widget.ConstraintLayout
        android:id="@+id/card"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        ...>

        <TextView
            android:id="@+id/short_text"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            ... />

        <TextView
            android:id="@+id/long_text"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:visibility="gone"
            .../>

    </androidx.constraintlayout.widget.ConstraintLayout>

Podczas pracy z przejściami przewidywanego przejścia wstecz pamiętaj o tych kwestiach:

  • Użyj isSeekingSupported, aby sprawdzić, czy przejście obsługuje przewidywane przejście wstecz.
  • Zastąp isSeekingSupported, aby zwracać wartość true w przypadku niestandardowych przejść.
  • Utwórz 1 kontroler na animację.
  • Przejścia przewidywanego przejścia wstecz są obsługiwane w przypadku przejść AndroidX, ale nie w przypadku przejść frameworka. Zmigruj z przejść frameworka i używaj zamiast nich Animator oraz przejść AndroidX.
  • Przejścia przewidywanego przejścia wstecz są obsługiwane na urządzeniach z Androidem 14 i nowszym i nie są zgodne wstecz.
  • Obsługiwane są też przejścia utworzone za pomocą scen XML. W handleOnBackStarted, ustaw TransitionSeekController na wynik z TransitionManager.createSeekController zamiast na wynik z controlDelayedTransition.

Dodatkowe materiały