לעיתים קרובות צריך לשנות את המיקום של אובייקטים על המסך בגלל אינטראקציה של המשתמש או עיבוד מאחורי הקלעים. במקום לעדכן מיד את מיקום האובייקט, שגורם לו להבהב מאזור אחד לאחר, אפשר להשתמש באנימציה כדי להזיז אותו מהמיקום ההתחלתי למיקום הסיום.
אחת הדרכים שבהן מערכת Android מאפשרת לשנות את מיקום האובייקטים במסך היא באמצעות ObjectAnimator
. מציינים את מיקום הסיום שבו רוצים שהאובייקט יעמוד, וגם את משך האנימציה. אפשר גם להשתמש באינטרפולטורים של זמן כדי לשלוט בהאצה או בהאטה של האנימציה.
שינוי מיקום התצוגה באמצעות ObjectAnimator
באמצעות ה-API ObjectAnimator
אפשר לשנות את המאפיינים של תצוגה מפורטת עם משך זמן ספציפי.
יש בו שיטות סטטיות ליצירת מופעים של ObjectAnimator
, בהתאם לסוג המאפיין שמונפש. כשמשנים את המיקום של התצוגות במסך, משתמשים במאפיינים translationX
ו-translationY
.
דוגמה ל-ObjectAnimator
שגורם להעברת התצוגה למיקום 100 פיקסלים מצד ימין של המסך תוך 2 שניות:
Kotlin
ObjectAnimator.ofFloat(view, "translationX", 100f).apply { duration = 2000 start() }
Java
ObjectAnimator animation = ObjectAnimator.ofFloat(view, "translationX", 100f); animation.setDuration(2000); animation.start();
בדוגמה הזו נעשה שימוש ב-method ObjectAnimator.ofFloat()
כי ערכי התרגום חייבים להיות מסוג צפים. הפרמטר הראשון הוא התצוגה שרוצים להוסיף לה אנימציה. הפרמטר השני הוא המאפיין שאתם יוצרים באנימציה. מכיוון שהתצוגה צריכה לזוז אופקית, נעשה שימוש במאפיין translationX
. הפרמטר האחרון הוא ערך הסיום של האנימציה. בדוגמה הזו, הערך 100 מציין מיקום של מספר פיקסלים גדול מהקצה השמאלי של המסך.
השיטה הבאה מציינת כמה זמן האנימציה נמשכת, באלפיות השנייה. בדוגמה הזו, האנימציה פועלת במשך 2 שניות (2,000 אלפיות השנייה).
השיטה האחרונה גורמת להפעלת האנימציה, שמעדכנת את המיקום של התצוגה במסך.
למידע נוסף על השימוש ב-ObjectAnimator
, ראו אנימציה באמצעות ObjectAnimator.
הוספת תנועה מעוקלת
השימוש ב-ObjectAnimator
נוח, אבל כברירת מחדל הוא ממקם מחדש את התצוגה לאורך קו ישר בין נקודת ההתחלה לנקודת הסיום. עיצוב Material מסתמך על עקומות לתנועה מרחבית של אובייקטים על המסך ולתזמון של האנימציה. תנועה מעוקלת הופכת את האפליקציה לחומרת יותר
ויוצרת אנימציות מעניינות יותר.
הגדרת הנתיב האישי
לכיתה ObjectAnimator
יש קונסטרוקטורים שמאפשרים ליצור אנימציה של קואורדינטות באמצעות שני נכסים או יותר בו-זמנית, יחד עם נתיב. לדוגמה, האנימציה הבאה משתמשת באובייקט Path
כדי להנפיש את המאפיינים X ו-Y של תצוגה:
Kotlin
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { val path = Path().apply { arcTo(0f, 0f, 1000f, 1000f, 270f, -180f, true) } val animator = ObjectAnimator.ofFloat(view, View.X, View.Y, path).apply { duration = 2000 start() } } else { // Create animator without using curved path }
Java
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { Path path = new Path(); path.arcTo(0f, 0f, 1000f, 1000f, 270f, -180f, true); ObjectAnimator animator = ObjectAnimator.ofFloat(view, View.X, View.Y, path); animator.setDuration(2000); animator.start(); } else { // Create animator without using curved path }
כך נראית אנימציית קשת:
איור 1. אנימציה של נתיב מעוקל.
Interpolator
הוא הטמעה של עקומת האטה. למידע נוסף על הקונספט של עקומות מעבר חלק, עיינו במסמכי התיעוד של Material Design. Interpolator
מגדיר איך ערכים ספציפיים באנימציה מחושבים כפונקציה של זמן. המערכת מספקת משאבי XML לשלוש העקומות הבסיסיות במפרט Material Design:
@interpolator/fast_out_linear_in.xml
@interpolator/fast_out_slow_in.xml
@interpolator/linear_out_slow_in.xml
שימוש ב-PathInterpolator
המחלקה PathInterpolator
היא אינטרפולטור שהושק ב-Android 5.0 (API 21). הוא מבוסס על עקומת ביז'ואר (Bézier) או על אובייקט Path
. הדוגמאות ל-Android במסמכי התיעוד של Material Design לצורך התאמה הן PathInterpolator
.
ל-PathInterpolator
יש בנאים המבוססים על סוגים שונים של עקומות של Bézier.
לכל העקומות של Bézier יש נקודות התחלה וסיום קבועות ב-(0,0)
וב-(1,1)
, בהתאמה. הארגומנטים האחרים של ה-constructor תלויים בסוג העקומה של Bézier שיוצרים.
לדוגמה, לעקומה של Bézier ריבועית, רק קואורדינטות ה-X וה-Y של נקודת בקרה אחת נדרשות:
Kotlin
val myInterpolator = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { PathInterpolator(0.67f, 0.33f) } else { LinearInterpolator() }
Java
Interpolator myInterpolator = null; if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { myInterpolator = new PathInterpolator(0.67f, 0.33f); } else { myInterpolator = new LinearInterpolator(); }
כך נוצרת עקומת האטה שמתחילה במהירות ומאטה ככל שהיא מתקרבת לסוף.
באופן דומה, למבנה של פונקציית Bézier חזקה יש נקודות התחלה וסיום קבועות, אבל הוא מחייב שתי נקודות בקרה:
Kotlin
val myInterpolator = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { PathInterpolator(0.5f, 0.7f, 0.1f, 1.0f) } else { LinearInterpolator() }
Java
Interpolator myInterpolator = null; if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { myInterpolator = new PathInterpolator(0.5f, 0.7f, 0.1f, 1.0f); } else { myInterpolator = new LinearInterpolator(); }
זהו יישום של עקומת ההתאמה מודגשת להאט של Material Design.
כדי להשיג שליטה טובה יותר, אפשר להשתמש בפונקציה Path
שרירותית כדי להגדיר את העקומה:
Kotlin
val myInterpolator = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { val path = Path().apply { moveTo(0.0f, 0.0f) cubicTo(0.5f, 0.7f, 0.1f, 1.0f, 1.0f, 1.0f) } PathInterpolator(path) } else { LinearInterpolator() }
Java
Interpolator myInterpolator = null; if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { Path path = new Path(); path.moveTo(0.0f, 0.0f); path.cubicTo(0.5f, 0.7f, 0.1f, 1.0f, 1.0f, 1.0f); myInterpolator = new PathInterpolator(path); } else { myInterpolator = new LinearInterpolator(); }
הפונקציה הזו יוצרת את אותה עקומת העברה כמו בדוגמה של פונקציית Bézier חזקה, אבל במקום זאת היא משתמשת ב-Path
.
אפשר גם להגדיר מתרגם נתיב כמשאב XML:
<pathInterpolator xmlns:android="http://schemas.android.com/apk/res/android"
android:controlX1="0.5"
android:controlY1="0.7"
android:controlX2="0.1f"
android:controlY2="1.0f"/>
אחרי שיוצרים אובייקט PathInterpolator
, אפשר להעביר אותו ל-method Animator.setInterpolator()
. ה-Animator
משתמש במערך האינטפולציה כדי לקבוע את התזמון או עקומת הנתיב כשהוא מופעל.
Kotlin
val animation = ObjectAnimator.ofFloat(view, "translationX", 100f).apply { interpolator = myInterpolator start() }
Java
ObjectAnimator animation = ObjectAnimator.ofFloat(view, "translationX", 100f); animation.setInterpolator(myInterpolator); animation.start();