เพิ่มการรองรับภาพเคลื่อนไหวของการย้อนกลับที่คาดการณ์ได้ใน Views

คุณสามารถสร้างภาพเคลื่อนไหวและภาพเคลื่อนไหวเปลี่ยนฉากของพร็อพเพอร์ตี้ในแอปที่กำหนดเอง ภาพเคลื่อนไหวข้ามกิจกรรมที่กำหนดเอง และภาพเคลื่อนไหวข้าม Fragment ที่กำหนดเองด้วยท่าทางย้อนกลับที่คาดการณ์ได้โดยใช้ View หรือ Compose หากต้องการลองใช้ Compose ให้ดู เพิ่มการรองรับภาพเคลื่อนไหวของการย้อนกลับที่คาดการณ์ได้

เพิ่มภาพเคลื่อนไหวเปลี่ยนฉากที่กำหนดเองโดยใช้ Progress API

เมื่อใช้ AndroidX Activity 1.8.0-alpha01 ขึ้นไป คุณจะใช้ Predictive Back Progress API เพื่อพัฒนาภาพเคลื่อนไหวที่กำหนดเองสำหรับท่าทางสัมผัสการย้อนกลับที่คาดการณ์ได้ในแอปได้ Progress API มีประโยชน์ในการสร้างภาพเคลื่อนไหวของ View แต่มีข้อจำกัดเมื่อสร้างภาพเคลื่อนไหวเปลี่ยนฉากระหว่าง Fragment เราได้เพิ่มเมธอด handleOnBackProgressed, handleOnBackCancelled และ handleOnBackStarted ภายใน OnBackPressedCallback เพื่อสร้างภาพเคลื่อนไหวของออบเจ็กต์ขณะที่ผู้ใช้ปัด กลับ ใช้เมธอดเหล่านี้หากคุณต้องการปรับแต่งภาพเคลื่อนไหวมากกว่าภาพเคลื่อนไหวเริ่มต้นที่ระบบหรือภาพเคลื่อนไหวของคอมโพเนนต์ 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 ต่อไปนี้แสดงภาพเคลื่อนไหวเปลี่ยนฉากที่กำหนดเองระหว่างกล่อง 2 กล่องที่ใช้ 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 เพื่อแสดงผลเป็น "จริง" สำหรับภาพเคลื่อนไหวเปลี่ยนฉากที่กำหนดเอง
  • สร้างคอนโทรลเลอร์ 1 รายการต่อภาพเคลื่อนไหว
  • ภาพเคลื่อนไหวเปลี่ยนฉากของการย้อนกลับที่คาดการณ์ได้รองรับภาพเคลื่อนไหวเปลี่ยนฉาก AndroidX แต่ไม่รองรับภาพเคลื่อนไหวเปลี่ยนฉากของเฟรมเวิร์ก ย้ายข้อมูลออกจากภาพเคลื่อนไหวเปลี่ยนฉากของเฟรมเวิร์กและใช้ Animator และภาพเคลื่อนไหวเปลี่ยนฉาก AndroidX แทน
  • ภาพเคลื่อนไหวเปลี่ยนฉากของการย้อนกลับที่คาดการณ์ได้รองรับอุปกรณ์ที่ใช้ Android 14 ขึ้นไปและไม่เข้ากันได้แบบย้อนกลับ
  • ระบบรองรับภาพเคลื่อนไหวเปลี่ยนฉากที่สร้างด้วยฉาก XML ด้วย ใน handleOnBackStarted ให้ตั้งค่า TransitionSeekController เป็นผลลัพธ์ ของ TransitionManager.createSeekController แทนผลลัพธ์ของ controlDelayedTransition

แหล่งข้อมูลเพิ่มเติม