העברת תצוגה עם אנימציה

רוצה לנסות את שיטת הכתיבה?
'Jetpack פיתוח נייטיב' היא ערכת הכלים המומלצת לממשק המשתמש ל-Android. איך משתמשים באנימציות ב-Compose

לעיתים קרובות צריך לשנות את המיקום של אובייקטים על המסך בגלל אינטראקציה של המשתמש או עיבוד מאחורי הקלעים. במקום לעדכן מיד את מיקום האובייקט, שגורם לו להבהב מאזור אחד לאחר, אפשר להשתמש באנימציה כדי להזיז אותו מהמיקום ההתחלתי למיקום הסיום.

אחת הדרכים שבהן מערכת 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();