הוספת תמיכה באנימציות של חיזוי החזרה בתצוגות

אתם יכולים ליצור אנימציות ומעברים מותאמים אישית של נכסים בתוך האפליקציה, אנימציות מותאמות אישית בין פעילויות ואנימציות מותאמות אישית בין קטעים עם תנועות ניווט חזויות אחורה באמצעות Views או Compose. כדי לנסות את השיטה של Compose, אפשר לעיין במאמר בנושא הוספת תמיכה באנימציות חזויות של חזרה.

הוספה של מעברים בהתאמה אישית באמצעות Progress API

אם משתמשים ב-AndroidX Activity בגרסה 1.8.0-alpha01 ומעלה, אפשר להשתמש בממשקי ה-API של התקדמות התנועה חזרה כדי לפתח אנימציות מותאמות אישית לתנועת החזרה החזויה באפליקציה. ממשקי ה-API של התקדמות התנועה חזרה שימושיים להנפשת תצוגות, אבל יש להם מגבלות כשמנפישים מעברים בין קטעים. ב-OnBackPressedCallback הוספנו את השיטות handleOnBackProgressed, handleOnBackCancelled ו-handleOnBackStarted כדי להנפיש אובייקטים בזמן שהמשתמש מחליק אחורה. אפשר להשתמש בשיטות האלה אם רוצים להתאים אישית יותר מאשר את האנימציות שמוגדרות כברירת מחדל במערכת, או את האנימציות של רכיבי Material.

אנחנו מצפים שרוב האפליקציות ישתמשו בממשקי AndroidX API שתואמים לגרסאות קודמות, אבל יש גם ממשקי API דומים לפלטפורמה בממשק OnBackAnimationCallback שזמינים לבדיקה ב-Android 14 ובגרסאות מתקדמות יותר.

שימוש בממשקי Progress API עם AndroidX Transitions

אפשר להשתמש בממשקי Progress API עם AndroidX Transitions בגרסה 1.5.0-alpha01 ואילך ב-Android 14 ואילך כדי ליצור מעברים של חזרה עם חיזוי.

  1. כדי להפעיל מעברים כשהמשתמש מחליק אחורה, צריך להשתמש ב-TransitionManager#controlDelayedTransition במקום ב-beginDelayedTransition.
  2. יוצרים את המעבר בתוך handleOnBackStarted.
  3. מפעילים את המעבר עם אירוע החזרה בתוך handleOnBackProgressed על ידי קישור currentFraction אל BackEvent.progress, וכך אפשר לראות עד כמה המשתמש החליק אחורה.
  4. השלמת המעבר אחרי שהמשתמש מבצע את תנועת החזרה ב-handleOnBackPressed.
  5. לבסוף, מאפסים את מצב המעבר בתוך handleOnBackCancelled.

בסרטון הבא, בקוד Kotlin וב-XML מוצגת דוגמה למעבר מותאם אישית בין שני תיבות שהוטמעו באמצעות 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>

כשעובדים עם מעברים של תצוגה מקדימה של חזרה, חשוב לזכור את הדברים הבאים:

  • משתמשים ב-isSeekingSupported כדי לבדוק אם המעבר תומך בתכונה 'חיזוי החזרה'.
  • מחליפים את isSeekingSupported כדי להחזיר true למעברים המותאמים אישית.
  • יוצרים בקר אחד לכל אנימציה.
  • מעברים עם חיזוי של חזרה אחורה נתמכים במעברים של AndroidX, אבל לא במעברים של framework. צריך להפסיק להשתמש במעברים של framework ולעבור לשימוש ב-Animator ובמעברים של AndroidX.
  • מעברים עם חיזוי של חזרה נתמכים במכשירים עם Android מגרסה 14 ואילך, והם לא תואמים לאחור.
  • יש תמיכה גם במעברים שנוצרו באמצעות סצנות XML. ב-handleOnBackStarted, מגדירים את TransitionSeekController לתוצאה של TransitionManager.createSeekController במקום לתוצאה של controlDelayedTransition.

מקורות מידע נוספים