ภาพรวมภาพเคลื่อนไหวของคุณสมบัติ

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

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

ระบบภาพเคลื่อนไหวของพร็อพเพอร์ตี้ช่วยให้คุณกำหนดลักษณะต่อไปนี้ของภาพเคลื่อนไหวได้

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

หากต้องการดูตัวอย่างภาพเคลื่อนไหวของพร็อพเพอร์ตี้ทั้งหมด โปรดดูคลาส ChangeColor ในตัวอย่าง CustomTransition ใน GitHub

วิธีการทำงานของภาพเคลื่อนไหวของพร็อพเพอร์ตี้

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

รูปที่ 1 ตัวอย่างภาพเคลื่อนไหวเชิงเส้น

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

รูปที่ 2 ตัวอย่างภาพเคลื่อนไหวแบบไม่เป็นเส้นตรง

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

รูปที่ 3 วิธีคำนวณภาพเคลื่อนไหว

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

ValueAnimator ห่อหุ้ม TimeInterpolator ซึ่งกำหนดการประมาณค่าภาพเคลื่อนไหว และ TypeEvaluator ซึ่งกำหนดวิธีคำนวณค่าสำหรับพร็อพเพอร์ตี้ที่กำลัง เคลื่อนไหว ตัวอย่างเช่น ในรูปที่ 2 TimeInterpolator ที่ใช้จะเป็น AccelerateDecelerateInterpolator และ TypeEvaluator จะเป็น IntEvaluator

หากต้องการเริ่มภาพเคลื่อนไหว ให้สร้าง ValueAnimator และกำหนดค่าเริ่มต้นและค่าสิ้นสุดสำหรับพร็อพเพอร์ตี้ที่ต้องการทำให้เคลื่อนไหว พร้อมกับระยะเวลาของภาพเคลื่อนไหว เมื่อคุณโทรหา start() ภาพเคลื่อนไหว จะเริ่มขึ้น ในระหว่างภาพเคลื่อนไหวทั้งหมด ValueAnimator จะคำนวณเศษส่วนที่ผ่านไป ระหว่าง 0 ถึง 1 โดยอิงตามระยะเวลาของภาพเคลื่อนไหวและระยะเวลาที่ผ่านไป เศษส่วนที่ผ่านไปแสดงถึงเปอร์เซ็นต์ของเวลาที่ภาพเคลื่อนไหวเสร็จสมบูรณ์ โดย 0 หมายถึง 0% และ 1 หมายถึง 100% ตัวอย่างเช่น ในรูปที่ 1 เศษส่วนที่ผ่านไปที่ t = 10 มิลลิวินาทีจะเป็น 0.25 เนื่องจากระยะเวลาทั้งหมดคือ t = 40 มิลลิวินาที

เมื่อ ValueAnimator คำนวณเศษส่วนที่ผ่านไปแล้ว TimeInterpolator ที่ตั้งค่าไว้ในปัจจุบันจะเรียกใช้เพื่อคำนวณเศษส่วนที่ประมาณค่า เศษส่วนที่ประมาณค่าจะแมปเศษส่วนที่ผ่านไปกับเศษส่วนใหม่ ซึ่งพิจารณาการประมาณค่าเวลาที่ตั้งไว้ ตัวอย่างเช่น ในรูปที่ 2 เนื่องจากภาพเคลื่อนไหวค่อยๆ เร่งความเร็ว เศษส่วนที่แทรกประมาณ 0.15 จึงน้อยกว่า เศษส่วนที่ผ่านไป 0.25 ที่ t = 10 มิลลิวินาที ในรูปที่ 1 เศษส่วนที่แทรกจะเท่ากับ เศษส่วนที่ผ่านไปเสมอ

เมื่อคำนวณเศษส่วนที่ประมาณค่าแล้ว ValueAnimator จะเรียก TypeEvaluator ที่เหมาะสมเพื่อคำนวณค่าของพร็อพเพอร์ตี้ที่คุณกำลังสร้างภาพเคลื่อนไหว โดยอิงตามเศษส่วนที่ประมาณค่า ค่าเริ่มต้น และค่าสิ้นสุดของภาพเคลื่อนไหว ตัวอย่างเช่น ในรูปที่ 2 เศษส่วนที่ประมาณค่าคือ .15 ที่ t = 10 มิลลิวินาที ดังนั้นค่าสำหรับพร็อพเพอร์ตี้ ณ เวลานั้นจะเป็น .15 × (40 - 0) หรือ 6

ความแตกต่างระหว่างภาพเคลื่อนไหวของพร็อพเพอร์ตี้กับภาพเคลื่อนไหวของมุมมอง

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

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

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

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

ภาพรวมของ API

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

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

ตารางที่ 1 แอนิเมเตอร์

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

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

ตารางที่ 2 ผู้ประเมิน

คลาส/อินเทอร์เฟซ คำอธิบาย
IntEvaluator เครื่องมือประเมินเริ่มต้นเพื่อคำนวณค่าสำหรับพร็อพเพอร์ตี้ int
FloatEvaluator เครื่องมือประเมินเริ่มต้นเพื่อคำนวณค่าสำหรับพร็อพเพอร์ตี้ float
ArgbEvaluator เครื่องประเมินเริ่มต้นเพื่อคำนวณค่าสำหรับพร็อพเพอร์ตี้สีที่แสดง เป็นค่าเลขฐานสิบหก
TypeEvaluator อินเทอร์เฟซที่ช่วยให้คุณสร้างผู้ประเมินของคุณเองได้ หากคุณกำลังทำให้พร็อพเพอร์ตี้ออบเจ็กต์ที่ไม่ใช่ int, float หรือสีเคลื่อนไหว คุณต้องใช้TypeEvaluatorอินเทอร์เฟซเพื่อระบุวิธี คำนวณค่าเคลื่อนไหวของพร็อพเพอร์ตี้ออบเจ็กต์ นอกจากนี้ คุณยังระบุ TypeEvaluator ที่กำหนดเองสำหรับค่า int, float และสีได้ด้วย หากต้องการประมวลผลค่าประเภทดังกล่าวแตกต่างจากลักษณะการทำงานเริ่มต้น ดูข้อมูลเพิ่มเติมเกี่ยวกับวิธีเขียนเครื่องมือประเมินที่กำหนดเองได้ในส่วนการใช้ TypeEvaluator

ตัวประมาณค่าเวลาจะกำหนดวิธีคำนวณค่าที่เฉพาะเจาะจงในภาพเคลื่อนไหวเป็นฟังก์ชันของเวลา เช่น คุณสามารถระบุให้ภาพเคลื่อนไหวเกิดขึ้นแบบเชิงเส้นตลอดทั้ง ภาพเคลื่อนไหว ซึ่งหมายความว่าภาพเคลื่อนไหวจะเคลื่อนที่อย่างสม่ำเสมอตลอดเวลา หรือคุณจะระบุให้ภาพเคลื่อนไหว ใช้เวลาแบบไม่เชิงเส้นก็ได้ เช่น เร่งความเร็วในช่วงต้นและลดความเร็วในช่วง ท้ายของภาพเคลื่อนไหว ตารางที่ 3 อธิบายตัวประมาณค่าที่อยู่ใน android.view.animation หากไม่มีตัวแทรกที่ตรงกับความต้องการของคุณ ให้ใช้ อินเทอร์เฟซ TimeInterpolator และสร้างตัวแทรกของคุณเอง ดูข้อมูลเพิ่มเติมเกี่ยวกับวิธีเขียน Interpolator ที่กำหนดเองได้ที่การใช้ Interpolator

ตารางที่ 3 ตัวกำหนดอัตราการเปลี่ยนแปลง

คลาส/อินเทอร์เฟซ คำอธิบาย
AccelerateDecelerateInterpolator ตัวแทรกค่าที่มีอัตราการเปลี่ยนแปลงที่เริ่มต้นและสิ้นสุดอย่างช้าๆ แต่จะเร่งความเร็ว ในช่วงกลาง
AccelerateInterpolator ตัวแทรกค่าที่มีอัตราการเปลี่ยนแปลงเริ่มต้นช้าและจากนั้น จะเร่งขึ้น
AnticipateInterpolator ตัวแทรกค่าที่มีการเปลี่ยนแปลงเริ่มต้นย้อนหลังแล้วพุ่งไปข้างหน้า
AnticipateOvershootInterpolator ตัวแทรกค่าที่มีการเปลี่ยนแปลงเริ่มต้นย้อนหลัง พุ่งไปข้างหน้าและเกิน ค่าเป้าหมาย จากนั้นจึงกลับไปที่ค่าสุดท้าย
BounceInterpolator ตัวแทรกที่การเปลี่ยนแปลงจะดีดกลับที่จุดสิ้นสุด
CycleInterpolator ตัวแทรกค่าที่ภาพเคลื่อนไหวจะเล่นซ้ำตามจำนวนรอบที่ระบุ
DecelerateInterpolator ตัวแทรกที่มีอัตราการเปลี่ยนแปลงเริ่มต้นอย่างรวดเร็วและจากนั้น จะชะลอตัว
LinearInterpolator ตัวประมาณค่าที่มีอัตราการเปลี่ยนแปลงคงที่
OvershootInterpolator ตัวแทรกค่าที่มีการเปลี่ยนแปลงพุ่งไปข้างหน้าและเกินค่าสุดท้าย แล้ว กลับมา
TimeInterpolator อินเทอร์เฟซที่ช่วยให้คุณติดตั้งใช้งานตัวประมาณค่าของคุณเองได้

สร้างภาพเคลื่อนไหวโดยใช้ ValueAnimator

คลาส ValueAnimator ช่วยให้คุณทำให้ค่าของประเภทบางอย่างเคลื่อนไหว ในระยะเวลาของภาพเคลื่อนไหวได้โดยการระบุชุดค่า int, float หรือสี เพื่อใช้ในการเคลื่อนไหว คุณจะได้รับ ValueAnimator โดยการเรียกใช้เมธอดจาก Factory อย่างใดอย่างหนึ่งต่อไปนี้ ofInt(), ofFloat() หรือ ofObject() เช่น

Kotlin

ValueAnimator.ofFloat(0f, 100f).apply {
    duration = 1000
    start()
}

Java

ValueAnimator animation = ValueAnimator.ofFloat(0f, 100f);
animation.setDuration(1000);
animation.start();

ในโค้ดนี้ ValueAnimator จะเริ่มคำนวณค่าของ ภาพเคลื่อนไหวระหว่าง 0 ถึง 100 เป็นระยะเวลา 1,000 มิลลิวินาที เมื่อเมธอด start() ทำงาน

นอกจากนี้ คุณยังระบุประเภทที่กำหนดเองเพื่อเคลื่อนไหวได้โดยทำดังนี้

Kotlin

ValueAnimator.ofObject(MyTypeEvaluator(), startPropertyValue, endPropertyValue).apply {
    duration = 1000
    start()
}

Java

ValueAnimator animation = ValueAnimator.ofObject(new MyTypeEvaluator(), startPropertyValue, endPropertyValue);
animation.setDuration(1000);
animation.start();

ในโค้ดนี้ ValueAnimator จะเริ่มคำนวณค่าของ ภาพเคลื่อนไหวระหว่าง startPropertyValue กับ endPropertyValue โดยใช้ ตรรกะที่ MyTypeEvaluator จัดหาให้เป็นระยะเวลา 1,000 มิลลิวินาที เมื่อเมธอด start() ทำงาน

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

Kotlin

ValueAnimator.ofObject(...).apply {
    ...
    addUpdateListener { updatedAnimation ->
        // You can use the animated value in a property that uses the
        // same type as the animation. In this case, you can use the
        // float value in the translationX property.
        textView.translationX = updatedAnimation.animatedValue as Float
    }
    ...
}

Java

animation.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
    @Override
    public void onAnimationUpdate(ValueAnimator updatedAnimation) {
        // You can use the animated value in a property that uses the
        // same type as the animation. In this case, you can use the
        // float value in the translationX property.
        float animatedValue = (float)updatedAnimation.getAnimatedValue();
        textView.setTranslationX(animatedValue);
    }
});

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

สร้างภาพเคลื่อนไหวโดยใช้ ObjectAnimator

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

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

Kotlin

ObjectAnimator.ofFloat(textView, "translationX", 100f).apply {
    duration = 1000
    start()
}

Java

ObjectAnimator animation = ObjectAnimator.ofFloat(textView, "translationX", 100f);
animation.setDuration(1000);
animation.start();

หากต้องการให้ ObjectAnimator อัปเดตพร็อพเพอร์ตี้ อย่างถูกต้อง คุณต้องทำดังนี้

  • พร็อพเพอร์ตี้ออบเจ็กต์ที่คุณกำลังเคลื่อนไหวต้องมีฟังก์ชัน Setter (ในรูปแบบ Camel Case) ในรูปแบบ set<PropertyName>() เนื่องจาก ObjectAnimator จะอัปเดตพร็อพเพอร์ตี้โดยอัตโนมัติระหว่างภาพเคลื่อนไหว จึงต้องเข้าถึงพร็อพเพอร์ตี้ ด้วยเมธอด Setter นี้ได้ เช่น หากชื่อพร็อพเพอร์ตี้คือ foo คุณจะต้องมีเมธอด setFoo() หากไม่มีเมธอดตัวตั้งค่านี้ คุณจะมีตัวเลือก 3 รายการ ดังนี้
    • เพิ่มเมธอด Setter ลงในคลาสหากคุณมีสิทธิ์ดำเนินการดังกล่าว
    • ใช้คลาส Wrapper ที่คุณมีสิทธิ์เปลี่ยนแปลง และให้ Wrapper รับค่า ด้วยเมธอด Setter ที่ถูกต้อง แล้วส่งต่อค่าไปยังออบเจ็กต์เดิม
    • ให้ใช้ ValueAnimator แทน
  • หากคุณระบุค่าเพียงค่าเดียวสำหรับพารามิเตอร์ values... ในเมธอด Factory ObjectAnimator อย่างใดอย่างหนึ่ง ระบบจะถือว่าค่าดังกล่าวเป็นค่าสิ้นสุดของ ภาพเคลื่อนไหว ดังนั้นพร็อพเพอร์ตี้ออบเจ็กต์ที่คุณกำลังเคลื่อนไหวต้องมีฟังก์ชัน Getter ที่ใช้เพื่อรับค่าเริ่มต้นของภาพเคลื่อนไหว ฟังก์ชัน Getter ต้องอยู่ในรูปแบบ get<PropertyName>() เช่น หากชื่อพร็อพเพอร์ตี้คือ foo คุณต้องมีเมธอด getFoo()
  • เมธอด Getter (หากจำเป็น) และ Setter ของพร็อพเพอร์ตี้ที่คุณกำลังเคลื่อนไหวต้อง ทำงานกับประเภทเดียวกันกับค่าเริ่มต้นและค่าสิ้นสุดที่คุณระบุให้กับ ObjectAnimator เช่น คุณต้องมี targetObject.setPropName(float) และ targetObject.getPropName() หากสร้าง ObjectAnimator ต่อไปนี้
    ObjectAnimator.ofFloat(targetObject, "propName", 1f)
  • คุณอาจต้องเรียกใช้เมธอด invalidate() ใน View เพื่อบังคับให้หน้าจอวาดซ้ำด้วยค่าเคลื่อนไหวที่อัปเดตแล้ว ทั้งนี้ขึ้นอยู่กับพร็อพเพอร์ตี้หรือออบเจ็กต์ที่กำลังเคลื่อนไหว คุณทำได้ใน onAnimationUpdate() การเรียกกลับ เช่น การเคลื่อนไหวพร็อพเพอร์ตี้สีของออบเจ็กต์ Drawable จะทําให้หน้าจออัปเดตเมื่อออบเจ็กต์วาดซ้ำเท่านั้น ตัวตั้งค่าพร็อพเพอร์ตี้ทั้งหมดใน View เช่น setAlpha() และ setTranslationX() จะลบล้าง View อย่างถูกต้อง คุณจึงไม่จำเป็นต้องลบล้าง View เมื่อเรียกใช้เมธอดเหล่านี้ ด้วยค่าใหม่ ดูข้อมูลเพิ่มเติมเกี่ยวกับ Listener ได้ที่ส่วนเกี่ยวกับ Animation Listener

ออกแบบท่าเต้นภาพเคลื่อนไหวหลายรายการโดยใช้ AnimatorSet

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

ข้อมูลโค้ดต่อไปนี้จะเล่นออบเจ็กต์ Animator ต่อไปนี้ในลักษณะต่อไปนี้

  1. เล่น bounceAnim
  2. เล่น squashAnim1, squashAnim2, stretchAnim1 และ stretchAnim2 พร้อมกัน
  3. เล่น bounceBackAnim
  4. เล่น fadeAnim

Kotlin

val bouncer = AnimatorSet().apply {
    play(bounceAnim).before(squashAnim1)
    play(squashAnim1).with(squashAnim2)
    play(squashAnim1).with(stretchAnim1)
    play(squashAnim1).with(stretchAnim2)
    play(bounceBackAnim).after(stretchAnim2)
}
val fadeAnim = ObjectAnimator.ofFloat(newBall, "alpha", 1f, 0f).apply {
    duration = 250
}
AnimatorSet().apply {
    play(bouncer).before(fadeAnim)
    start()
}

Java

AnimatorSet bouncer = new AnimatorSet();
bouncer.play(bounceAnim).before(squashAnim1);
bouncer.play(squashAnim1).with(squashAnim2);
bouncer.play(squashAnim1).with(stretchAnim1);
bouncer.play(squashAnim1).with(stretchAnim2);
bouncer.play(bounceBackAnim).after(stretchAnim2);
ValueAnimator fadeAnim = ObjectAnimator.ofFloat(newBall, "alpha", 1f, 0f);
fadeAnim.setDuration(250);
AnimatorSet animatorSet = new AnimatorSet();
animatorSet.play(bouncer).before(fadeAnim);
animatorSet.start();

Animation listeners

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

  • Animator.AnimatorListener
    • onAnimationStart() - เรียกใช้เมื่อภาพเคลื่อนไหวเริ่ม
    • onAnimationEnd() - เรียกใช้เมื่อภาพเคลื่อนไหวสิ้นสุด
    • onAnimationRepeat() - เรียกใช้เมื่อภาพเคลื่อนไหวเล่นซ้ำ
    • onAnimationCancel() - เรียกใช้เมื่อมีการยกเลิกภาพเคลื่อนไหว ภาพเคลื่อนไหวที่ยกเลิก จะเรียกใช้ onAnimationEnd() ด้วย ไม่ว่าภาพเคลื่อนไหวจะสิ้นสุดลงอย่างไรก็ตาม
  • ValueAnimator.AnimatorUpdateListener
    • onAnimationUpdate() - เรียกใช้ในทุกเฟรมของภาพเคลื่อนไหว ฟังเหตุการณ์นี้เพื่อ ใช้ค่าที่คํานวณแล้วซึ่งสร้างโดย ValueAnimator ระหว่าง ภาพเคลื่อนไหว หากต้องการใช้ค่า ให้ค้นหาออบเจ็กต์ ValueAnimator ที่ส่งไปยังเหตุการณ์เพื่อรับค่าเคลื่อนไหวปัจจุบันด้วยเมธอด getAnimatedValue() คุณต้องใช้เครื่อง รับฟังนี้หากใช้ ValueAnimator

      คุณอาจต้องเรียกใช้ invalidate() ใน View เพื่อบังคับให้พื้นที่นั้นของ หน้าจอวาดใหม่ด้วยค่าเคลื่อนไหวใหม่ ทั้งนี้ขึ้นอยู่กับพร็อพเพอร์ตี้หรือออบเจ็กต์ที่กำลังเคลื่อนไหว เช่น การเคลื่อนไหวพร็อพเพอร์ตี้สีของออบเจ็กต์ Drawable จะทําให้หน้าจออัปเดตเมื่อออบเจ็กต์นั้นวาดซ้ำเท่านั้น ตัวตั้งค่าพร็อพเพอร์ตี้ทั้งหมดใน View เช่น setAlpha() และ setTranslationX() จะทำให้ View ไม่ถูกต้องอย่างเหมาะสม คุณจึงไม่จำเป็นต้องทำให้ View ไม่ถูกต้องเมื่อเรียกใช้เมธอดเหล่านี้ด้วยค่าใหม่

คุณสามารถขยายคลาส AnimatorListenerAdapter แทนการ ใช้Animator.AnimatorListenerอินเทอร์เฟซได้ หากไม่ต้องการ ใช้เมธอดทั้งหมดของอินเทอร์เฟซ Animator.AnimatorListener คลาส AnimatorListenerAdapter มีการติดตั้งใช้งานเมธอดที่ว่างเปล่า ซึ่งคุณเลือกที่จะลบล้างได้

ตัวอย่างเช่น ข้อมูลโค้ดต่อไปนี้จะสร้าง AnimatorListenerAdapter สำหรับแฮนเดิลการเรียกกลับ onAnimationEnd() เท่านั้น

Kotlin

ObjectAnimator.ofFloat(newBall, "alpha", 1f, 0f).apply {
    duration = 250
    addListener(object : AnimatorListenerAdapter() {
        override fun onAnimationEnd(animation: Animator) {
            balls.remove((animation as ObjectAnimator).target)
        }
    })
}

Java

ValueAnimator fadeAnim = ObjectAnimator.ofFloat(newBall, "alpha", 1f, 0f);
fadeAnim.setDuration(250);
fadeAnim.addListener(new AnimatorListenerAdapter() {
public void onAnimationEnd(Animator animation) {
    balls.remove(((ObjectAnimator)animation).getTarget());
}

สร้างภาพเคลื่อนไหวการเปลี่ยนแปลงเลย์เอาต์ไปยังออบเจ็กต์ ViewGroup

ระบบภาพเคลื่อนไหวของพร็อพเพอร์ตี้ช่วยให้สามารถสร้างภาพเคลื่อนไหวของการเปลี่ยนแปลงออบเจ็กต์ ViewGroup รวมถึงให้วิธีง่ายๆ ในการสร้างภาพเคลื่อนไหวของออบเจ็กต์ View เอง

คุณสามารถเคลื่อนไหวการเปลี่ยนแปลงเลย์เอาต์ภายใน ViewGroup ได้ด้วยคลาส LayoutTransition View ภายใน ViewGroup สามารถ ผ่านภาพเคลื่อนไหวการปรากฏและหายไปเมื่อคุณเพิ่มหรือ นำออกจาก ViewGroup หรือเมื่อคุณเรียกใช้เมธอด setVisibility() ของ View ด้วย VISIBLE, INVISIBLE หรือ GONE นอกจากนี้ View ที่เหลือใน ViewGroup ยัง เคลื่อนไหวไปยังตำแหน่งใหม่ได้เมื่อคุณเพิ่มหรือนำ View ออก คุณกำหนดภาพเคลื่อนไหวต่อไปนี้ในออบเจ็กต์ LayoutTransition ได้โดยเรียก setAnimator() และส่งออบเจ็กต์ Animator ที่มีค่าคงที่ LayoutTransition อย่างใดอย่างหนึ่งต่อไปนี้

  • APPEARING - แฟล็กที่ระบุภาพเคลื่อนไหวที่ทำงานกับรายการที่ ปรากฏในคอนเทนเนอร์
  • CHANGE_APPEARING - แฟล็กที่ระบุภาพเคลื่อนไหวที่ทำงานกับรายการที่ เปลี่ยนแปลงเนื่องจากมีรายการใหม่ปรากฏในคอนเทนเนอร์
  • DISAPPEARING - แฟล็กที่ระบุภาพเคลื่อนไหวที่ทำงานกับรายการที่ หายไปจากคอนเทนเนอร์
  • CHANGE_DISAPPEARING - แฟล็กที่ระบุภาพเคลื่อนไหวที่ทำงานกับรายการที่ มีการเปลี่ยนแปลงเนื่องจากรายการหายไปจากคอนเทนเนอร์

คุณสามารถกําหนดภาพเคลื่อนไหวที่กําหนดเองสําหรับเหตุการณ์ 4 ประเภทนี้เพื่อปรับแต่งลักษณะ ของการเปลี่ยนเลย์เอาต์ หรือเพียงแค่บอกระบบภาพเคลื่อนไหวให้ใช้ภาพเคลื่อนไหวเริ่มต้น

หากต้องการตั้งค่าแอตทริบิวต์ android:animateLayoutchanges เป็น true สำหรับ ViewGroup ให้ทำดังนี้

<LinearLayout
    android:orientation="vertical"
    android:layout_width="wrap_content"
    android:layout_height="match_parent"
    android:id="@+id/verticalContainer"
    android:animateLayoutChanges="true" />

การตั้งค่าแอตทริบิวต์นี้เป็น true จะทําให้ View ที่เพิ่มหรือนําออกจาก ViewGroup รวมถึง View ที่เหลือใน ViewGroup เคลื่อนไหวโดยอัตโนมัติ

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

คลาส StateListAnimator ช่วยให้คุณกำหนดแอนิเมเตอร์ที่จะทำงานเมื่อ สถานะของมุมมองเปลี่ยนแปลง ออบเจ็กต์นี้ทําหน้าที่เป็น Wrapper สําหรับออบเจ็กต์ Animator โดยเรียกใช้ภาพเคลื่อนไหวนั้นเมื่อใดก็ตามที่สถานะของ View ที่ระบุ (เช่น "กด" หรือ "โฟกัส") เปลี่ยนแปลง

คุณกำหนด StateListAnimator ได้ในทรัพยากร XML ที่มีองค์ประกอบรูท <selector> และองค์ประกอบย่อย <item> ซึ่งแต่ละองค์ประกอบจะระบุสถานะมุมมองที่แตกต่างกันซึ่งกำหนดโดยคลาส StateListAnimator แต่ละ <item> มีคำจำกัดความสำหรับชุดภาพเคลื่อนไหวของพร็อพเพอร์ตี้

ตัวอย่างเช่น ไฟล์ต่อไปนี้จะสร้างแอนิเมเตอร์รายการสถานะที่เปลี่ยนสเกล x และ y ของมุมมองเมื่อมีการกด

res/xml/animate_scale.xml

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <!-- the pressed state; increase x and y size to 150% -->
    <item android:state_pressed="true">
        <set>
            <objectAnimator android:propertyName="scaleX"
                android:duration="@android:integer/config_shortAnimTime"
                android:valueTo="1.5"
                android:valueType="floatType"/>
            <objectAnimator android:propertyName="scaleY"
                android:duration="@android:integer/config_shortAnimTime"
                android:valueTo="1.5"
                android:valueType="floatType"/>
        </set>
    </item>
    <!-- the default, non-pressed state; set x and y size to 100% -->
    <item android:state_pressed="false">
        <set>
            <objectAnimator android:propertyName="scaleX"
                android:duration="@android:integer/config_shortAnimTime"
                android:valueTo="1"
                android:valueType="floatType"/>
            <objectAnimator android:propertyName="scaleY"
                android:duration="@android:integer/config_shortAnimTime"
                android:valueTo="1"
                android:valueType="floatType"/>
        </set>
    </item>
</selector>

หากต้องการแนบแอนิเมเตอร์รายการสถานะกับ View ให้เพิ่มแอตทริบิวต์ android:stateListAnimator ดังนี้

<Button android:stateListAnimator="@xml/animate_scale"
        ... />

ตอนนี้ระบบจะใช้ภาพเคลื่อนไหวที่กำหนดไว้ใน animate_scale.xml เมื่อสถานะของปุ่มนี้เปลี่ยนไป

หรือหากต้องการกำหนด StateListAnimator ให้กับ View ในโค้ดแทน ให้ใช้เมธอด AnimatorInflater.loadStateListAnimator() และกำหนด Animator ให้กับ View ด้วยเมธอด View.setStateListAnimator()

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

<!-- res/drawable/myanimstatedrawable.xml -->
<animated-selector
    xmlns:android="http://schemas.android.com/apk/res/android">

    <!-- provide a different drawable for each state-->
    <item android:id="@+id/pressed" android:drawable="@drawable/drawableP"
        android:state_pressed="true"/>
    <item android:id="@+id/focused" android:drawable="@drawable/drawableF"
        android:state_focused="true"/>
    <item android:id="@id/default"
        android:drawable="@drawable/drawableD"/>

    <!-- specify a transition -->
    <transition android:fromId="@+id/default" android:toId="@+id/pressed">
        <animation-list>
            <item android:duration="15" android:drawable="@drawable/dt1"/>
            <item android:duration="15" android:drawable="@drawable/dt2"/>
            ...
        </animation-list>
    </transition>
    ...
</animated-selector>

ใช้ TypeEvaluator

หากต้องการเคลื่อนไหวประเภทที่ระบบ Android ไม่รู้จัก คุณสามารถสร้างเครื่องประเมินของคุณเองได้โดยการใช้TypeEvaluatorอินเทอร์เฟซ ประเภทที่ระบบ Android รู้จักคือ int, float หรือสี ซึ่งได้รับการรองรับโดยตัวประเมินประเภท IntEvaluator, FloatEvaluator และ ArgbEvaluator

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

Kotlin

private class FloatEvaluator : TypeEvaluator<Any> {

    override fun evaluate(fraction: Float, startValue: Any, endValue: Any): Any {
        return (startValue as Number).toFloat().let { startFloat ->
            startFloat + fraction * ((endValue as Number).toFloat() - startFloat)
        }
    }

}

Java

public class FloatEvaluator implements TypeEvaluator {

    public Object evaluate(float fraction, Object startValue, Object endValue) {
        float startFloat = ((Number) startValue).floatValue();
        return startFloat + fraction * (((Number) endValue).floatValue() - startFloat);
    }
}

หมายเหตุ: เมื่อ ValueAnimator (หรือ ObjectAnimator) ทำงาน ระบบจะคำนวณเศษส่วนที่ผ่านไปปัจจุบันของ ภาพเคลื่อนไหว (ค่าระหว่าง 0 ถึง 1) แล้วคำนวณเวอร์ชันที่แทรกค่าของเศษส่วนนั้นโดยขึ้นอยู่กับ ตัวแทรกค่าที่คุณใช้ เศษส่วนที่ประมาณค่าคือสิ่งที่ TypeEvaluator ได้รับผ่านพารามิเตอร์ fraction ดังนั้นคุณจึงไม่จำเป็นต้องพิจารณาตัวประมาณค่าเมื่อคำนวณค่าภาพเคลื่อนไหว

ใช้ Interpolators

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

Interpolators ในระบบภาพเคลื่อนไหวจะได้รับเศษส่วนจาก Animators ซึ่งแสดงถึง เวลาที่ผ่านไปของภาพเคลื่อนไหว Interpolator จะแก้ไขเศษส่วนนี้ให้สอดคล้องกับประเภทของ ภาพเคลื่อนไหวที่ต้องการแสดง ระบบ Android มีชุดตัวประมาณค่าทั่วไปใน android.view.animation package หากไม่มีตัวเลือกใดที่เหมาะกับความต้องการของคุณ คุณสามารถใช้TimeInterpolatorอินเทอร์เฟซและสร้าง อินเทอร์เฟซของคุณเองได้

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

AccelerateDecelerateInterpolator

Kotlin

override fun getInterpolation(input: Float): Float =
        (Math.cos((input + 1) * Math.PI) / 2.0f).toFloat() + 0.5f

Java

@Override
public float getInterpolation(float input) {
    return (float)(Math.cos((input + 1) * Math.PI) / 2.0f) + 0.5f;
}

LinearInterpolator

Kotlin

override fun getInterpolation(input: Float): Float = input

Java

@Override
public float getInterpolation(float input) {
    return input;
}

ตารางต่อไปนี้แสดงค่าโดยประมาณที่ตัวแทรกค่า เหล่านี้คำนวณสำหรับการเคลื่อนไหวที่มีระยะเวลา 1,000 มิลลิวินาที

ms elapsed เศษส่วนที่ผ่านไป/เศษส่วนที่ประมาณค่า (เชิงเส้น) เศษส่วนที่ประมาณค่า (เร่ง/ชะลอ)
0 0 0
200 .2 .1
400 .4 .345
600 .6 .654
800 .8 .9
1000 1 1

ดังที่ตารางแสดง LinearInterpolator จะเปลี่ยนค่า ด้วยความเร็วเดียวกัน คือ 0.2 ทุกๆ 200 มิลลิวินาที AccelerateDecelerateInterpolator จะเปลี่ยนค่าเร็วกว่า LinearInterpolator ระหว่าง 200 มิลลิวินาทีถึง 600 มิลลิวินาที และช้ากว่าระหว่าง 600 มิลลิวินาทีถึง 1,000 มิลลิวินาที

ระบุคีย์เฟรม

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

หากต้องการสร้างออบเจ็กต์ Keyframe คุณต้องใช้วิธีการของ Factory อย่างใดอย่างหนึ่ง ได้แก่ ofInt(), ofFloat() หรือ ofObject() เพื่อรับ Keyframe ประเภทที่เหมาะสม จากนั้นคุณจะเรียกใช้ เมธอด Factory ofKeyframe() เพื่อ รับออบเจ็กต์ PropertyValuesHolder เมื่อมีออบเจ็กต์แล้ว คุณจะ รับแอนิเมเตอร์ได้โดยส่งPropertyValuesHolderออบเจ็กต์และ ออบเจ็กต์ที่จะเคลื่อนไหว ข้อมูลโค้ดต่อไปนี้แสดงวิธีดำเนินการนี้

Kotlin

val kf0 = Keyframe.ofFloat(0f, 0f)
val kf1 = Keyframe.ofFloat(.5f, 360f)
val kf2 = Keyframe.ofFloat(1f, 0f)
val pvhRotation = PropertyValuesHolder.ofKeyframe("rotation", kf0, kf1, kf2)
ObjectAnimator.ofPropertyValuesHolder(target, pvhRotation).apply {
    duration = 5000
}

Java

Keyframe kf0 = Keyframe.ofFloat(0f, 0f);
Keyframe kf1 = Keyframe.ofFloat(.5f, 360f);
Keyframe kf2 = Keyframe.ofFloat(1f, 0f);
PropertyValuesHolder pvhRotation = PropertyValuesHolder.ofKeyframe("rotation", kf0, kf1, kf2);
ObjectAnimator rotationAnim = ObjectAnimator.ofPropertyValuesHolder(target, pvhRotation);
rotationAnim.setDuration(5000);

ทำให้มุมมองเคลื่อนไหว

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

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

  • translationX และ translationY: คุณสมบัติเหล่านี้จะควบคุมตำแหน่งของ View เป็นเดลต้าจากพิกัดซ้ายและบนซึ่งกำหนดโดยคอนเทนเนอร์เลย์เอาต์
  • rotation, rotationX และ rotationY: พร็อพเพอร์ตี้เหล่านี้ ควบคุมการหมุนใน 2 มิติ (พร็อพเพอร์ตี้ rotation) และ 3 มิติรอบจุดหมุน
  • scaleX และ scaleY: พร็อพเพอร์ตี้เหล่านี้ควบคุมการปรับขนาด 2 มิติของ View รอบจุดหมุน
  • pivotX และ pivotY: พร็อพเพอร์ตี้เหล่านี้ควบคุมตำแหน่งของ จุดแกนหมุน ซึ่งการหมุนและการปรับขนาดจะเกิดขึ้นรอบๆ จุดนี้ โดยค่าเริ่มต้น จุดหมุน จะอยู่ที่กึ่งกลางของออบเจ็กต์
  • x และ y: คุณสมบัติยูทิลิตีแบบง่ายเหล่านี้ใช้เพื่ออธิบาย ตำแหน่งสุดท้ายของมุมมองในคอนเทนเนอร์ ซึ่งเป็นผลรวมของค่าด้านซ้ายและด้านบน รวมถึงค่า translationX และ translationY
  • alpha: แสดงความโปร่งใสของอัลฟ่าใน View ค่านี้จะเป็น 1 (ทึบแสง) โดยค่าเริ่มต้น โดยค่า 0 หมายถึงความโปร่งใสทั้งหมด (มองไม่เห็น)

หากต้องการเคลื่อนไหวพร็อพเพอร์ตี้ของออบเจ็กต์ View เช่น ค่าสีหรือการหมุน สิ่งที่คุณต้องทำคือสร้าง PropertyAnimator และระบุพร็อพเพอร์ตี้ View ที่ต้องการเคลื่อนไหว เช่น

Kotlin

ObjectAnimator.ofFloat(myView, "rotation", 0f, 360f)

Java

ObjectAnimator.ofFloat(myView, "rotation", 0f, 360f);

ดูข้อมูลเพิ่มเติมเกี่ยวกับการสร้างแอนิเมเตอร์ได้ในส่วนการสร้างภาพเคลื่อนไหวด้วย ValueAnimator และ ObjectAnimator

สร้างภาพเคลื่อนไหวโดยใช้ ViewPropertyAnimator

ViewPropertyAnimator ช่วยให้คุณเคลื่อนไหวพร็อพเพอร์ตี้หลายรายการของ View ได้อย่างง่ายดาย พร้อมกันโดยใช้ออบเจ็กต์ Animator พื้นฐานเพียงรายการเดียว โดยจะทำงานคล้ายกับ ObjectAnimator เนื่องจากจะแก้ไขค่าจริงของพร็อพเพอร์ตี้ของวิว แต่จะมีประสิทธิภาพมากกว่าเมื่อทำให้พร็อพเพอร์ตี้หลายรายการเคลื่อนไหวพร้อมกัน นอกจากนี้ โค้ดสำหรับใช้ ViewPropertyAnimator ยังกระชับและอ่านง่ายกว่ามาก ข้อมูลโค้ดต่อไปนี้แสดงความแตกต่างในการใช้ออบเจ็กต์ ObjectAnimator หลายรายการ, ObjectAnimator รายการเดียว และ ViewPropertyAnimator เมื่อทำให้พร็อพเพอร์ตี้ x และ y ของมุมมองเคลื่อนไหวพร้อมกัน

ออบเจ็กต์ ObjectAnimator หลายรายการ

Kotlin

val animX = ObjectAnimator.ofFloat(myView, "x", 50f)
val animY = ObjectAnimator.ofFloat(myView, "y", 100f)
AnimatorSet().apply {
    playTogether(animX, animY)
    start()
}

Java

ObjectAnimator animX = ObjectAnimator.ofFloat(myView, "x", 50f);
ObjectAnimator animY = ObjectAnimator.ofFloat(myView, "y", 100f);
AnimatorSet animSetXY = new AnimatorSet();
animSetXY.playTogether(animX, animY);
animSetXY.start();

ObjectAnimator หนึ่งรายการ

Kotlin

val pvhX = PropertyValuesHolder.ofFloat("x", 50f)
val pvhY = PropertyValuesHolder.ofFloat("y", 100f)
ObjectAnimator.ofPropertyValuesHolder(myView, pvhX, pvhY).start()

Java

PropertyValuesHolder pvhX = PropertyValuesHolder.ofFloat("x", 50f);
PropertyValuesHolder pvhY = PropertyValuesHolder.ofFloat("y", 100f);
ObjectAnimator.ofPropertyValuesHolder(myView, pvhX, pvhY).start();

ViewPropertyAnimator

Kotlin

myView.animate().x(50f).y(100f)

Java

myView.animate().x(50f).y(100f);

ดูข้อมูลโดยละเอียดเกี่ยวกับ ViewPropertyAnimator ได้ในบล็อก โพสต์ที่เกี่ยวข้องของนักพัฒนาแอป Android

ประกาศภาพเคลื่อนไหวใน XML

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

หากต้องการแยกความแตกต่างระหว่างไฟล์ภาพเคลื่อนไหวที่ใช้ Property Animation API ใหม่กับไฟล์ที่ใช้เฟรมเวิร์กภาพเคลื่อนไหวของมุมมองเดิม ตั้งแต่ Android 3.1 เป็นต้นไป คุณควรบันทึกไฟล์ XML สำหรับ Property Animation ไว้ในไดเรกทอรี res/animator/

คลาสภาพเคลื่อนไหวของพร็อพเพอร์ตี้ต่อไปนี้รองรับการประกาศ XML ด้วยแท็ก XML ต่อไปนี้

หากต้องการดูแอตทริบิวต์ที่ใช้ในการประกาศ XML ได้ ให้ดูแหล่งข้อมูลภาพเคลื่อนไหว ตัวอย่างต่อไปนี้จะเล่นภาพเคลื่อนไหวของออบเจ็กต์ 2 ชุด ตามลําดับ โดยชุดที่ซ้อนกันชุดแรกจะเล่นภาพเคลื่อนไหวของออบเจ็กต์ 2 รายการพร้อมกัน

<set android:ordering="sequentially">
    <set>
        <objectAnimator
            android:propertyName="x"
            android:duration="500"
            android:valueTo="400"
            android:valueType="intType"/>
        <objectAnimator
            android:propertyName="y"
            android:duration="500"
            android:valueTo="300"
            android:valueType="intType"/>
    </set>
    <objectAnimator
        android:propertyName="alpha"
        android:duration="500"
        android:valueTo="1f"/>
</set>

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

Kotlin

(AnimatorInflater.loadAnimator(myContext, R.animator.property_animator) as AnimatorSet).apply {
    setTarget(myObject)
    start()
}

Java

AnimatorSet set = (AnimatorSet) AnimatorInflater.loadAnimator(myContext,
    R.animator.property_animator);
set.setTarget(myObject);
set.start();

คุณยังประกาศ ValueAnimator ใน XML ได้ด้วย ดังที่แสดงในตัวอย่างต่อไปนี้

<animator xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="1000"
    android:valueType="floatType"
    android:valueFrom="0f"
    android:valueTo="-100f" />

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

Kotlin

(AnimatorInflater.loadAnimator(this, R.animator.animator) as ValueAnimator).apply {
    addUpdateListener { updatedAnimation ->
        textView.translationX = updatedAnimation.animatedValue as Float
    }

    start()
}

Java

ValueAnimator xmlAnimator = (ValueAnimator) AnimatorInflater.loadAnimator(this,
        R.animator.animator);
xmlAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
    @Override
    public void onAnimationUpdate(ValueAnimator updatedAnimation) {
        float animatedValue = (float)updatedAnimation.getAnimatedValue();
        textView.setTranslationX(animatedValue);
    }
});

xmlAnimator.start();

ดูข้อมูลเกี่ยวกับไวยากรณ์ XML สำหรับการกำหนดภาพเคลื่อนไหวของพร็อพเพอร์ตี้ได้ที่แหล่งข้อมูลภาพเคลื่อนไหว

ผลกระทบที่อาจมีต่อประสิทธิภาพ UI

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

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