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

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

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

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

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

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

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

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

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

สร้างฉาก

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

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

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

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

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

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

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

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

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

  • เลย์เอาต์หลักของกิจกรรมที่มีป้ายกำกับข้อความและ child FrameLayout
  • A 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>

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

หลังจากสร้างคำจำกัดความสำหรับเลย์เอาต์ Constraint 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 ตามด้วย a 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 รายการที่เกือบจะเหมือนกัน แทนที่จะสร้างและดูแลไฟล์เลย์เอาต์ 2 ไฟล์แยกกันสำหรับความแตกต่างเล็กน้อยในอินเทอร์เฟซผู้ใช้ คุณสามารถมีไฟล์เลย์เอาต์ 1 ไฟล์ที่มีลำดับชั้นการแสดงผลที่คุณแก้ไขในโค้ด

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

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

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

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

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.

กำหนดฟังก์ชันเรียกกลับของวงจรชีวิตการเปลี่ยน

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

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

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

ข้อจำกัด

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

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