สร้างภาพเคลื่อนไหวการเปลี่ยนแปลงการออกแบบโดยใช้การเปลี่ยน

ลองใช้วิธีแบบ Compose
Jetpack Compose เป็นชุดเครื่องมือ UI ที่แนะนำสำหรับ Android ดูวิธีใช้ภาพเคลื่อนไหวใน Compose

เฟรมเวิร์กการเปลี่ยนของ Android ช่วยให้คุณสร้างภาพเคลื่อนไหวการเคลื่อนไหวทุกประเภทใน UI ได้โดยระบุเลย์เอาต์เริ่มต้นและเลย์เอาต์สิ้นสุด คุณเลือกประเภทภาพเคลื่อนไหวที่ต้องการได้ เช่น ให้มุมมองค่อยๆ ปรากฏหรือหายไป หรือเปลี่ยนขนาดมุมมอง และเฟรมเวิร์กการเปลี่ยนจะกำหนดวิธีสร้างภาพเคลื่อนไหวจากเลย์เอาต์เริ่มต้นไปยังเลย์เอาต์สุดท้าย

กรอบการเปลี่ยนผ่านมีฟีเจอร์ต่อไปนี้

  • ภาพเคลื่อนไหวระดับกลุ่ม: ใช้เอฟเฟกต์ภาพเคลื่อนไหวกับมุมมองทั้งหมดในลำดับชั้นการแสดงผล
  • ภาพเคลื่อนไหวในตัว: ใช้ภาพเคลื่อนไหวที่กำหนดไว้ล่วงหน้าสำหรับเอฟเฟกต์ทั่วไป เช่น การจางออกหรือการเคลื่อนไหว
  • การรองรับไฟล์ทรัพยากร: โหลดลําดับชั้นของมุมมองและภาพเคลื่อนไหวในตัวจากไฟล์ทรัพยากรเลย์เอาต์
  • Lifecycle Callback: รับ Callback ที่ให้การควบคุมกระบวนการเปลี่ยนภาพเคลื่อนไหวและลำดับชั้น

ดูโค้ดตัวอย่างที่เคลื่อนไหวระหว่างการเปลี่ยนแปลงเลย์เอาต์ได้ที่ BasicTransition

ขั้นตอนพื้นฐานในการเปลี่ยนภาพเคลื่อนไหวระหว่างเลย์เอาต์ 2 แบบมีดังนี้

  1. สร้างออบเจ็กต์ Scene สำหรับเลย์เอาต์เริ่มต้นและเลย์เอาต์สิ้นสุด อย่างไรก็ตาม ฉากของเลย์เอาต์เริ่มต้นมักจะกำหนดโดยอัตโนมัติจากเลย์เอาต์ปัจจุบัน
  2. สร้างออบเจ็กต์ Transition เพื่อกำหนดประเภทภาพเคลื่อนไหวที่ต้องการ
  3. เรียก TransitionManager.go() และระบบจะเรียกใช้ภาพเคลื่อนไหวเพื่อสลับเลย์เอาต์

แผนภาพในรูปที่ 1 แสดงความสัมพันธ์ระหว่างเลย์เอาต์ ฉาก การเปลี่ยนฉาก และภาพเคลื่อนไหวสุดท้าย

รูปที่ 1 ภาพพื้นฐานของ วิธีที่เฟรมเวิร์กการเปลี่ยนสร้างภาพเคลื่อนไหว

สร้างฉาก

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

คุณสร้างฉากจากไฟล์เลย์เอาต์ ทรัพยากรหรือจากกลุ่มมุมมองในโค้ดได้ อย่างไรก็ตาม ระบบมักจะกำหนดฉากเริ่มต้นสำหรับการเปลี่ยนฉากโดยอัตโนมัติจาก UI ปัจจุบัน

นอกจากนี้ ฉากยังกำหนดการกระทำของตัวเองที่จะทำงานเมื่อคุณเปลี่ยนฉากได้ด้วย ฟีเจอร์นี้มีประโยชน์ในการล้างการตั้งค่ามุมมองหลังจาก เปลี่ยนไปใช้ฉาก

สร้างฉากจากทรัพยากรเลย์เอาต์

คุณสร้างSceneอินสแตนซ์ได้โดยตรงจากไฟล์ทรัพยากรเลย์เอาต์ ใช้เทคนิคนี้เมื่อลำดับชั้นของมุมมองในไฟล์ส่วนใหญ่เป็นแบบคงที่ ฉากที่ได้จะแสดงสถานะของลําดับชั้นของมุมมองในเวลาที่คุณสร้างอินสแตนซ์ Scene หากเปลี่ยนลำดับชั้นการแสดงผล ให้สร้างฉากใหม่ เฟรมเวิร์กจะสร้างฉากจากลำดับชั้นมุมมองทั้งหมดในไฟล์ คุณสร้างฉากจากส่วนหนึ่งของไฟล์เลย์เอาต์ไม่ได้

หากต้องการสร้างอินสแตนซ์ Scene จากไฟล์ทรัพยากรเลย์เอาต์ ให้ดึงข้อมูล รูทฉากจากเลย์เอาต์เป็น ViewGroup จากนั้นเรียกฟังก์ชัน Scene.getSceneForLayout() โดยใช้รูทของฉากและรหัสทรัพยากรของไฟล์เลย์เอาต์ที่ มีลำดับชั้นของมุมมองสำหรับฉาก

กำหนดเลย์เอาต์สำหรับฉาก

ข้อมูลโค้ดในส่วนที่เหลือของส่วนนี้แสดงวิธีสร้าง 2 ฉากที่แตกต่างกันโดยใช้องค์ประกอบรากของฉากเดียวกัน นอกจากนี้ ข้อมูลโค้ดยังแสดงให้เห็นว่าคุณโหลดออบเจ็กต์ Scene ที่ไม่เกี่ยวข้องหลายรายการได้โดยไม่ต้องระบุว่าออบเจ็กต์เหล่านั้นเกี่ยวข้องซึ่งกันและกัน

ตัวอย่างประกอบด้วยคำจำกัดความของเลย์เอาต์ต่อไปนี้

  • เลย์เอาต์หลักของกิจกรรมที่มีป้ายกำกับข้อความและองค์ประกอบย่อย FrameLayout
  • ConstraintLayout สำหรับฉากแรกที่มีช่องข้อความ 2 ช่อง
  • ConstraintLayout สำหรับฉากที่ 2 โดยมีช่องข้อความ 2 ช่องเดียวกันใน ลำดับที่แตกต่างกัน

ตัวอย่างนี้ออกแบบมาเพื่อให้ภาพเคลื่อนไหวทั้งหมดเกิดขึ้นภายในเลย์เอาต์ย่อยของเลย์เอาต์หลักสำหรับกิจกรรม ป้ายกำกับข้อความในเลย์เอาต์หลัก จะยังคงเป็นแบบคงที่

เลย์เอาต์หลักของกิจกรรมมีการกําหนดดังนี้

res/layout/activity_main.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/master_layout">
    <TextView
        android:id="@+id/title"
        ...
        android:text="Title"/>
    <FrameLayout
        android:id="@+id/scene_root">
        <include layout="@layout/a_scene" />
    </FrameLayout>
</LinearLayout>

คำจำกัดความเลย์เอาต์นี้มีช่องข้อความและองค์ประกอบย่อย FrameLayout สำหรับ รูทของฉาก เลย์เอาต์สำหรับฉากแรกจะรวมอยู่ในไฟล์เลย์เอาต์หลัก ซึ่งจะช่วยให้แอปแสดงเป็นส่วนหนึ่งของอินเทอร์เฟซผู้ใช้เริ่มต้นและโหลดลงในฉากได้ เนื่องจากเฟรมเวิร์กจะโหลดได้เฉพาะไฟล์เลย์เอาต์ทั้งไฟล์ลงในฉาก

เลย์เอาต์ของฉากแรกมีการกำหนดดังนี้

res/layout/a_scene.xml

<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/scene_container"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >
    <TextView
        android:id="@+id/text_view1"
        android:layout_height="wrap_content"
        android:layout_width="wrap_content"
        android:text="Text Line 1"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toEndOf="parent"/>
    <TextView
        android:id="@+id/text_view2"
        android:layout_height="wrap_content"
        android:layout_width="wrap_content"
        android:text="Text Line 2"
        app:layout_constraintTop_toBottomOf="@id/text_view1"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toEndOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

เลย์เอาต์ของฉากที่ 2 มีช่องข้อความ 2 ช่องเดียวกัน โดยมีรหัสเดียวกัน แต่จัดเรียงในลำดับที่ต่างกัน โดยมีคำจำกัดความดังนี้

res/layout/another_scene.xml

<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/scene_container"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >
    <TextView
        android:id="@+id/text_view2"
        android:layout_height="wrap_content"
        android:layout_width="wrap_content"
        android:text="Text Line 2"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toEndOf="parent" />
    <TextView
        android:id="@+id/text_view1"
        android:layout_height="wrap_content"
        android:layout_width="wrap_content"
        android:text="Text Line 1"
        app:layout_constraintTop_toBottomOf="@id/text_view2"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toEndOf="parent"/>
</androidx.constraintlayout.widget.ConstraintLayout>

สร้างฉากจากเลย์เอาต์

หลังจากสร้างคำจำกัดความสำหรับ ConstraintLayout ทั้ง 2 รายการแล้ว คุณจะรับ ฉากสำหรับแต่ละรายการได้ ซึ่งช่วยให้คุณเปลี่ยนระหว่างการกำหนดค่า UI ทั้ง 2 แบบได้ หากต้องการรับฉาก คุณต้องมีข้อมูลอ้างอิงไปยังรูทของฉากและรหัสทรัพยากรเลย์เอาต์

ข้อมูลโค้ดต่อไปนี้แสดงวิธีรับการอ้างอิงไปยังรูทของฉากและสร้างออบเจ็กต์ Scene 2 รายการจากไฟล์เลย์เอาต์

Kotlin

val sceneRoot: ViewGroup = findViewById(R.id.scene_root)
val aScene: Scene = Scene.getSceneForLayout(sceneRoot, R.layout.a_scene, this)
val anotherScene: Scene = Scene.getSceneForLayout(sceneRoot, R.layout.another_scene, this)

Java

Scene aScene;
Scene anotherScene;

// Create the scene root for the scenes in this app.
sceneRoot = (ViewGroup) findViewById(R.id.scene_root);

// Create the scenes.
aScene = Scene.getSceneForLayout(sceneRoot, R.layout.a_scene, this);
anotherScene =
    Scene.getSceneForLayout(sceneRoot, R.layout.another_scene, this);

ตอนนี้ในแอปมีออบเจ็กต์ Scene 2 รายการตามลำดับชั้นของมุมมอง ทั้ง 2 ฉากใช้รูทฉากที่กำหนดโดยองค์ประกอบ FrameLayout ใน res/layout/activity_main.xml

สร้างฉากในโค้ด

นอกจากนี้ คุณยังสร้างSceneอินสแตนซ์ในโค้ดจากออบเจ็กต์ ViewGroup ได้ด้วย ใช้เทคนิคนี้เมื่อคุณแก้ไขลำดับชั้นของมุมมอง ในโค้ดโดยตรงหรือเมื่อคุณสร้างลำดับชั้นแบบไดนามิก

หากต้องการสร้างฉากจากลำดับชั้นของมุมมองในโค้ด ให้ใช้ตัวสร้าง Scene(sceneRoot, viewHierarchy) การเรียกใช้ตัวสร้างนี้เทียบเท่ากับการเรียกใช้ฟังก์ชัน Scene.getSceneForLayout() เมื่อคุณขยายไฟล์เลย์เอาต์แล้ว

ข้อมูลโค้ดต่อไปนี้แสดงวิธีสร้างอินสแตนซ์ Scene จากองค์ประกอบรูทของฉากและลำดับชั้นการแสดงผลสำหรับฉากในโค้ด

Kotlin

val sceneRoot = someLayoutElement as ViewGroup
val viewHierarchy = someOtherLayoutElement as ViewGroup
val scene: Scene = Scene(sceneRoot, viewHierarchy)

Java

Scene mScene;

// Obtain the scene root element.
sceneRoot = (ViewGroup) someLayoutElement;

// Obtain the view hierarchy to add as a child of
// the scene root when this scene is entered.
viewHierarchy = (ViewGroup) someOtherLayoutElement;

// Create a scene.
mScene = new Scene(sceneRoot, mViewHierarchy);

สร้างการกระทำในฉาก

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

การดำเนินการในฉากมีประโยชน์ในการจัดการกรณีต่อไปนี้

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

หากต้องการระบุการดำเนินการในฉากที่กำหนดเอง ให้กำหนดการดำเนินการเป็นออบเจ็กต์ Runnable แล้วส่งไปยังฟังก์ชัน Scene.setExitAction() หรือ Scene.setEnterAction() เฟรมเวิร์กจะเรียกใช้ฟังก์ชัน setExitAction() ในฉากเริ่มต้นก่อนที่จะเรียกใช้ภาพเคลื่อนไหวของการเปลี่ยนฉาก และเรียกใช้ฟังก์ชัน setEnterAction() ในฉากสิ้นสุดหลังจากเรียกใช้ภาพเคลื่อนไหวของการเปลี่ยนฉาก

ใช้การเปลี่ยนผ่าน

เฟรมเวิร์กการเปลี่ยนผ่านแสดงถึงรูปแบบของภาพเคลื่อนไหวระหว่างฉากที่มีออบเจ็กต์ Transition คุณสามารถสร้างอินสแตนซ์ของ Transition ได้โดยใช้คลาสย่อยในตัว เช่น AutoTransition และ Fade หรือกำหนดการเปลี่ยนผ่านของคุณเอง จากนั้นคุณจะเรียกใช้ ภาพเคลื่อนไหวระหว่างฉากได้โดยส่งScene Transition ไปยัง TransitionManager.go()

วงจรการเปลี่ยนคล้ายกับวงจรกิจกรรม และแสดงถึง สถานะการเปลี่ยนที่เฟรมเวิร์กตรวจสอบระหว่างจุดเริ่มต้นและ จุดสิ้นสุดของภาพเคลื่อนไหว ในสถานะวงจรที่สำคัญ เฟรมเวิร์กจะเรียกใช้ฟังก์ชันเรียกกลับที่คุณสามารถใช้เพื่อปรับอินเทอร์เฟซผู้ใช้ในระยะต่างๆ ของการเปลี่ยนผ่าน

สร้างการเปลี่ยนฉาก

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

ตารางที่ 1 ประเภทการเปลี่ยนในตัว

ชั้น แท็ก เอฟเฟ็กต์
AutoTransition <autoTransition/> การเปลี่ยนผ่านเริ่มต้น จางออก ย้ายและปรับขนาด รวมถึงจางเข้าในมุมมองตามลำดับ
ChangeBounds <changeBounds/> ย้ายและปรับขนาดมุมมอง
ChangeClipBounds <changeClipBounds/> จับภาพView.getClipBounds()ก่อนและหลังฉาก เปลี่ยน และเคลื่อนไหวการเปลี่ยนแปลงเหล่านั้นในระหว่างการเปลี่ยนฉาก
ChangeImageTransform <changeImageTransform/> บันทึกเมทริกซ์ของ ImageView ก่อนและหลังการเปลี่ยนฉาก และเคลื่อนไหวระหว่างการเปลี่ยนฉาก
ChangeScroll <changeScroll/> บันทึกพร็อพเพอร์ตี้การเลื่อนของเป้าหมายก่อนและหลังการเปลี่ยนแปลงฉาก และเคลื่อนไหวการเปลี่ยนแปลงใดๆ
ChangeTransform <changeTransform/> บันทึกขนาดและการหมุนของมุมมองก่อนและหลังการเปลี่ยนฉาก และเคลื่อนไหวการเปลี่ยนแปลงเหล่านั้นในระหว่างการเปลี่ยนฉาก
Explode <explode/> ติดตามการเปลี่ยนแปลงระดับการมองเห็นของมุมมองเป้าหมายในฉากเริ่มต้นและฉากสิ้นสุด และย้ายมุมมองเข้าหรือออกจากขอบของฉาก
Fade <fade/> fade_in จะค่อยๆ ปรากฏในมุมมอง
fade_out จะทำให้มุมมองจางลง
fade_in_out (ค่าเริ่มต้น) จะทำ fade_out ตามด้วย fade_in
Slide <slide/> ติดตามการเปลี่ยนแปลงระดับการมองเห็นของมุมมองเป้าหมายในฉากเริ่มต้นและฉากสิ้นสุด และย้ายมุมมองเข้าหรือออกจากขอบด้านใดด้านหนึ่งของฉาก

สร้างอินสแตนซ์การเปลี่ยนฉากจากไฟล์ทรัพยากร

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

หากต้องการระบุภาพเคลื่อนไหวในตัวในไฟล์ทรัพยากร ให้ทำตามขั้นตอนต่อไปนี้

  • เพิ่มไดเรกทอรี res/transition/ ลงในโปรเจ็กต์
  • สร้างไฟล์ทรัพยากร XML ใหม่ภายในไดเรกทอรีนี้
  • เพิ่มโหนด XML สำหรับทรานซิชันบิวท์อินรายการใดรายการหนึ่ง

เช่น ไฟล์ทรัพยากรต่อไปนี้จะระบุFadeการเปลี่ยนฉาก

res/transition/fade_transition.xml

<fade xmlns:android="http://schemas.android.com/apk/res/android" />

ข้อมูลโค้ดต่อไปนี้แสดงวิธีขยายอินสแตนซ์ Transition ภายใน กิจกรรมจากไฟล์ทรัพยากร

Kotlin

var fadeTransition: Transition =
    TransitionInflater.from(this)
                      .inflateTransition(R.transition.fade_transition)

Java

Transition fadeTransition =
        TransitionInflater.from(this).
        inflateTransition(R.transition.fade_transition);

สร้างอินสแตนซ์การเปลี่ยนในโค้ด

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

หากต้องการสร้างอินสแตนซ์ของการเปลี่ยนฉากในตัว ให้เรียกใช้เครื่องมือสร้างสาธารณะอย่างใดอย่างหนึ่งในคลาสย่อยของคลาส Transition ตัวอย่างเช่น ข้อมูลโค้ดต่อไปนี้จะสร้างอินสแตนซ์ของการเปลี่ยน Fade

Kotlin

var fadeTransition: Transition = Fade()

Java

Transition fadeTransition = new Fade();

ใช้การเปลี่ยนผ่าน

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

หากต้องการเปลี่ยนฉากขณะใช้การเปลี่ยนฉากเพื่อตอบสนองต่อเหตุการณ์ในกิจกรรม ให้เรียกใช้ฟังก์ชันคลาส TransitionManager.go() โดยใช้ฉากสิ้นสุดและอินสแตนซ์การเปลี่ยนฉากที่จะใช้สำหรับภาพเคลื่อนไหว ดังที่แสดงในข้อมูลโค้ดต่อไปนี้

Kotlin

TransitionManager.go(endingScene, fadeTransition)

Java

TransitionManager.go(endingScene, fadeTransition);

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

หากคุณไม่ได้ระบุอินสแตนซ์การเปลี่ยนผ่าน ตัวจัดการการเปลี่ยนผ่านจะใช้การเปลี่ยนผ่านอัตโนมัติที่ทําสิ่งที่สมเหตุสมผลสําหรับสถานการณ์ส่วนใหญ่ได้ ดูข้อมูลเพิ่มเติมได้ที่เอกสารอ้างอิง API สำหรับคลาส TransitionManager

เลือกมุมมองเป้าหมายที่เฉพาะเจาะจง

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

แต่ละมุมมองที่การเปลี่ยนภาพเคลื่อนไหวเรียกว่าเป้าหมาย คุณเลือกได้เฉพาะเป้าหมายที่เป็นส่วนหนึ่งของลําดับชั้นของมุมมองที่เชื่อมโยงกับฉาก

หากต้องการนำข้อมูลพร็อพเพอร์ตี้อย่างน้อย 1 รายการออกจากรายการเป้าหมาย ให้เรียกใช้เมธอด removeTarget() ก่อนเริ่มการเปลี่ยน หากต้องการเพิ่มเฉพาะมุมมองที่คุณระบุลงใน รายการเป้าหมาย ให้เรียกใช้ฟังก์ชัน addTarget() ดูข้อมูลเพิ่มเติมได้ที่การอ้างอิง API สำหรับคลาส Transition

ระบุทรานซิชันหลายรายการ

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

คุณไม่จำเป็นต้องเลือกภาพเคลื่อนไหวเพียงรายการเดียว เนื่องจากเฟรมเวิร์กการเปลี่ยนฉาก ช่วยให้คุณรวมเอฟเฟกต์ภาพเคลื่อนไหวไว้ในการเปลี่ยนฉากชุดเดียวที่มีกลุ่ม การเปลี่ยนฉากในตัวหรือการเปลี่ยนฉากที่กำหนดเองแต่ละรายการได้

หากต้องการกำหนดชุดการเปลี่ยนฉากจากคอลเล็กชันการเปลี่ยนฉากใน XML ให้สร้างไฟล์ทรัพยากรในไดเรกทอรี res/transitions/ และแสดงรายการการเปลี่ยนฉากภายใต้องค์ประกอบ TransitionSet ตัวอย่างเช่น ข้อมูลโค้ดต่อไปนี้แสดงวิธี ระบุชุดการเปลี่ยนที่มีลักษณะการทำงานเหมือนกับคลาส AutoTransition

<transitionSet xmlns:android="http://schemas.android.com/apk/res/android"
    android:transitionOrdering="sequential">
    <fade android:fadingMode="fade_out" />
    <changeBounds />
    <fade android:fadingMode="fade_in" />
</transitionSet>

หากต้องการขยายชุดการเปลี่ยนเป็นออบเจ็กต์ TransitionSet ในโค้ด ให้เรียกใช้ฟังก์ชัน TransitionInflater.from() ในกิจกรรม คลาส TransitionSet ขยายจากคลาส Transition คุณจึงใช้คลาสนี้กับเครื่องมือจัดการการเปลี่ยนฉากได้เช่นเดียวกับอินสแตนซ์ Transition อื่นๆ

ใช้การเปลี่ยนผ่านโดยไม่มีฉาก

การเปลี่ยนลําดับชั้นของมุมมองไม่ใช่เพียงวิธีเดียวในการแก้ไขอินเทอร์เฟซผู้ใช้ นอกจากนี้ คุณยังทำการเปลี่ยนแปลงได้โดยการเพิ่ม แก้ไข และนำมุมมองของบุตรหลานออกภายใน ลำดับชั้นปัจจุบัน

ตัวอย่างเช่น คุณสามารถใช้การโต้ตอบการค้นหาด้วย เลย์เอาต์เดียว เริ่มต้นด้วยเลย์เอาต์ที่แสดงช่องป้อนข้อมูลการค้นหาและไอคอนค้นหา หากต้องการเปลี่ยนอินเทอร์เฟซผู้ใช้เพื่อแสดงผลลัพธ์ ให้นำปุ่มค้นหาออก เมื่อผู้ใช้แตะปุ่มดังกล่าวโดยเรียกใช้ฟังก์ชัน ViewGroup.removeView() และเพิ่มผลการค้นหาโดยเรียกใช้ฟังก์ชัน ViewGroup.addView()

คุณใช้วิธีนี้ได้หากทางเลือกอื่นคือการมีลำดับชั้น 2 ระดับที่ เกือบจะเหมือนกัน คุณสามารถมีไฟล์เลย์เอาต์ไฟล์เดียว ซึ่งมีลำดับชั้นของ View ที่คุณแก้ไขในโค้ดได้ แทนที่จะสร้างและดูแลรักษาไฟล์เลย์เอาต์ 2 ไฟล์แยกกัน สำหรับความแตกต่างเล็กน้อยในอินเทอร์เฟซผู้ใช้

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

หากต้องการสร้างการเปลี่ยนฉากที่ล่าช้าภายในลําดับชั้นของมุมมองเดียว ให้ทําตาม ขั้นตอนต่อไปนี้

  1. เมื่อเกิดเหตุการณ์ที่ทริกเกอร์การเปลี่ยน ให้เรียกใช้ฟังก์ชัน TransitionManager.beginDelayedTransition() โดยระบุมุมมองหลักของมุมมองทั้งหมด ที่คุณต้องการเปลี่ยนและการเปลี่ยนที่จะใช้ เฟรมเวิร์กจะจัดเก็บสถานะปัจจุบันของมุมมองย่อยและค่าพร็อพเพอร์ตี้
  2. ทําการเปลี่ยนแปลงมุมมองของเด็กตามที่กรณีการใช้งานของคุณต้องการ เฟรมเวิร์ก จะบันทึกการเปลี่ยนแปลงที่คุณทำกับข้อมูลพร็อพเพอร์ตี้ของมุมมองย่อย
  3. เมื่อระบบวาดอินเทอร์เฟซผู้ใช้ใหม่ตามการเปลี่ยนแปลงของคุณ เฟรมเวิร์กจะเคลื่อนไหวการเปลี่ยนแปลงระหว่างสถานะเดิมกับสถานะใหม่

ตัวอย่างต่อไปนี้แสดงวิธีสร้างภาพเคลื่อนไหวของการเพิ่ม TextView ลงในลำดับชั้นของ View โดยใช้การเปลี่ยนฉากที่ล่าช้า ข้อมูลโค้ดแรกแสดงไฟล์คำจำกัดความของเลย์เอาต์

res/layout/activity_main.xml

<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/mainLayout"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >
    <EditText
        android:id="@+id/inputText"
        android:layout_alignParentLeft="true"
        android:layout_alignParentTop="true"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toEndOf="parent" />
    ...
</androidx.constraintlayout.widget.ConstraintLayout>

ข้อมูลโค้ดถัดไปแสดงโค้ดที่เคลื่อนไหวการเพิ่มมุมมองข้อความ

กิจกรรมหลัก

Kotlin

setContentView(R.layout.activity_main)
val labelText = TextView(this).apply {
    text = "Label"
    id = R.id.text
}
val rootView: ViewGroup = findViewById(R.id.mainLayout)
val mFade: Fade = Fade(Fade.IN)
TransitionManager.beginDelayedTransition(rootView, mFade)
rootView.addView(labelText)

Java

private TextView labelText;
private Fade mFade;
private ViewGroup rootView;
...
// Load the layout.
setContentView(R.layout.activity_main);
...
// Create a new TextView and set some View properties.
labelText = new TextView(this);
labelText.setText("Label");
labelText.setId(R.id.text);

// Get the root view and create a transition.
rootView = (ViewGroup) findViewById(R.id.mainLayout);
mFade = new Fade(Fade.IN);

// Start recording changes to the view hierarchy.
TransitionManager.beginDelayedTransition(rootView, mFade);

// Add the new TextView to the view hierarchy.
rootView.addView(labelText);

// When the system redraws the screen to show this update,
// the framework animates the addition as a fade in.

กำหนด Lifecycle Callback การเปลี่ยนผ่าน

วงจรการเปลี่ยนผ่านจะคล้ายกับวงจรกิจกรรม ซึ่งแสดงถึง สถานะการเปลี่ยนผ่านที่เฟรมเวิร์กตรวจสอบในช่วงเวลาระหว่างการเรียก ฟังก์ชัน TransitionManager.go() กับการสิ้นสุด ภาพเคลื่อนไหว ในสถานะวงจรการใช้งานที่สำคัญ เฟรมเวิร์กจะเรียกใช้การเรียกกลับ ที่กำหนดโดยอินเทอร์เฟซ TransitionListener

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

ดูข้อมูลเพิ่มเติมได้ที่การอ้างอิง API สำหรับคลาส TransitionListener

ข้อจำกัด

ส่วนนี้จะแสดงข้อจำกัดที่ทราบบางประการของเฟรมเวิร์กการเปลี่ยนฉาก

  • ภาพเคลื่อนไหวที่ใช้กับ SurfaceView อาจไม่ปรากฏ อย่างถูกต้อง อินสแตนซ์ SurfaceView จะได้รับการอัปเดตจากเธรดที่ไม่ใช่ UI ดังนั้นการอัปเดตอาจไม่ซิงค์กับภาพเคลื่อนไหวของมุมมองอื่นๆ
  • การเปลี่ยนฉากบางประเภทอาจไม่สร้างเอฟเฟกต์ภาพเคลื่อนไหวที่ต้องการ เมื่อใช้กับTextureView
  • คลาสที่ขยายเวลา AdapterView เช่น ListView จัดการมุมมองย่อยในลักษณะที่ไม่สอดคล้องกับ เฟรมเวิร์กการเปลี่ยนผ่าน หากคุณพยายามเคลื่อนไหวมุมมองโดยอิงตาม AdapterView จอแสดงผลของอุปกรณ์อาจหยุดตอบสนอง
  • หากพยายามปรับขนาด TextView ที่มีภาพเคลื่อนไหว ข้อความจะปรากฏในตำแหน่งใหม่ก่อนที่ออบเจ็กต์จะปรับขนาดเสร็จสมบูรณ์ อย่าเคลื่อนไหวการปรับขนาดของมุมมองที่มีข้อความเพื่อหลีกเลี่ยงปัญหานี้