הרבה ממשקי Animation API מקבלים בדרך כלל פרמטרים להתאמה אישית של ההתנהגות שלהם.
התאמה אישית של אנימציות באמצעות הפרמטר AnimationSpec
רוב ממשקי ה-Animation API מאפשרים למפתחים להתאים אישית את מפרטי האנימציה באמצעות פרמטר AnimationSpec אופציונלי.
val alpha: Float by animateFloatAsState( targetValue = if (enabled) 1f else 0.5f, // Configure the animation duration and easing. animationSpec = tween(durationMillis = 300, easing = FastOutSlowInEasing), label = "alpha" )
יש סוגים שונים של AnimationSpec ליצירת סוגים שונים של אנימציה.
יצירת אנימציה שמבוססת על פיזיקה באמצעות spring
spring יוצר אנימציה שמבוססת על פיזיקה בין ערכי ההתחלה והסיום. היא מקבלת 2 פרמטרים: dampingRatio ו-stiffness.
dampingRatio מגדיר את מידת הקפיציות של הקפיץ. ערך ברירת המחדל הוא Spring.DampingRatioNoBouncy.
הערך stiffness מגדיר את המהירות שבה הקפיץ צריך לנוע לעבר ערך הסיום. ערך ברירת המחדל הוא Spring.StiffnessMedium.
val value by animateFloatAsState( targetValue = 1f, animationSpec = spring( dampingRatio = Spring.DampingRatioHighBouncy, stiffness = Spring.StiffnessMedium ), label = "spring spec" )
הפונקציה spring יכולה לטפל בהפרעות בצורה חלקה יותר מאשר סוגי AnimationSpec שמבוססים על משך זמן, כי היא מבטיחה את המשכיות המהירות כשערך היעד משתנה במהלך האנימציות. spring משמש כברירת המחדל של AnimationSpec בהרבה ממשקי API של אנימציה, כמו animate*AsState ו-updateTransition.
לדוגמה, אם נחיל הגדרה של spring על האנימציה הבאה שמופעלת על ידי מגע של המשתמש, כשנפריע לאנימציה בזמן שהיא מתקדמת, אפשר לראות שהשימוש ב-tween לא מגיב בצורה חלקה כמו השימוש ב-spring.
tween לעומת spring לאנימציה, והפסקת האנימציה.הנפשה בין ערכי ההתחלה והסיום עם עקומת האטה באמצעות tween
הפונקציה tween יוצרת אנימציה בין ערכי ההתחלה והסיום במהלך durationMillis שצוין באמצעות עקומת האטה. tween הוא קיצור של המילה between (בין) – כי הוא עובר בין שני ערכים.
אפשר גם לציין delayMillis כדי לדחות את תחילת האנימציה.
val value by animateFloatAsState( targetValue = 1f, animationSpec = tween( durationMillis = 300, delayMillis = 50, easing = LinearOutSlowInEasing ), label = "tween delay" )
מידע נוסף זמין במאמר בנושא האצה והאטה.
אנימציה של ערכים ספציפיים בתזמונים מסוימים באמצעות keyframes
keyframes יוצר אנימציה על סמך ערכי תמונת המצב שצוינו בחותמות זמן שונות במהלך האנימציה. בכל רגע נתון, ערך האנימציה יחושב בין שני ערכים של פריים מרכזי. לכל אחד מפריים המפתח האלה, אפשר לציין את ההאטה כדי לקבוע את עקומת האינטרפולציה.
אפשר לציין את הערכים ב-0 אלפיות השנייה ובמשך הזמן, אבל לא חובה. אם לא מציינים את הערכים האלה, הם מוגדרים כברירת מחדל לערכי ההתחלה והסיום של האנימציה, בהתאמה.
val value by animateFloatAsState( targetValue = 1f, animationSpec = keyframes { durationMillis = 375 0.0f at 0 using LinearOutSlowInEasing // for 0-15 ms 0.2f at 15 using FastOutLinearInEasing // for 15-75 ms 0.4f at 75 // ms 0.4f at 225 // ms }, label = "keyframe" )
אנימציה חלקה בין פריימים מרכזיים באמצעות keyframesWithSpline
כדי ליצור אנימציה שעוקבת אחרי עקומה חלקה כשהיא עוברת בין ערכים, אפשר להשתמש במפרטי האנימציה של keyframesWithSpline במקום keyframes.
val offset by animateOffsetAsState( targetValue = Offset(300f, 300f), animationSpec = keyframesWithSpline { durationMillis = 6000 Offset(0f, 0f) at 0 Offset(150f, 200f) atFraction 0.5f Offset(0f, 100f) atFraction 0.7f } )
פריימים מרכזיים שמבוססים על עקומות שימושיים במיוחד לתנועה דו-ממדית של פריטים במסך.
בסרטונים הבאים מוצגים ההבדלים בין keyframes לבין keyframesWithSpline, בהתאם לאותה קבוצה של קואורדינטות x ו-y שמעגל צריך לעקוב אחריהן.
keyframes
|
keyframesWithSpline
|
|---|---|
כמו שאתם רואים, הקיפריימים שמבוססים על עקומות מציעים מעברים חלקים יותר בין הנקודות, כי הם משתמשים בעקומות בזייה כדי ליצור אנימציה חלקה בין הפריטים. המפרט הזה שימושי לאנימציה מוגדרת מראש. עם זאת, אם אתם עובדים עם נקודות שמונעות על ידי המשתמש, עדיף להשתמש בקפיצים כדי להשיג חלקות דומה בין הנקודות, כי אפשר להפריע להן.
חזרה על אנימציה עם repeatable
repeatable מריץ אנימציה שמבוססת על משך זמן (כמו tween או keyframes) שוב ושוב עד שהוא מגיע למספר החזרות שצוין. אפשר להעביר את הפרמטר repeatMode כדי לציין אם האנימציה צריכה לחזור על עצמה מההתחלה (RepeatMode.Restart) או מהסוף (RepeatMode.Reverse).
val value by animateFloatAsState( targetValue = 1f, animationSpec = repeatable( iterations = 3, animation = tween(durationMillis = 300), repeatMode = RepeatMode.Reverse ), label = "repeatable spec" )
חזרה על אנימציה בלי הפסקה באמצעות infiniteRepeatable
infiniteRepeatable דומה ל-repeatable, אבל חוזר על עצמו מספר אינסופי של פעמים.
val value by animateFloatAsState( targetValue = 1f, animationSpec = infiniteRepeatable( animation = tween(durationMillis = 300), repeatMode = RepeatMode.Reverse ), label = "infinite repeatable" )
בבדיקות שמשתמשות ב-ComposeTestRule, אנימציות שמשתמשות ב-infiniteRepeatable לא פועלות. הרכיב יעובד באמצעות הערך הראשוני של כל ערך מונפש.
מעבר מיידי לערך הסופי באמצעות snap
snap היא פונקציית AnimationSpec מיוחדת שמשנה מיד את הערך לערך הסופי. אפשר לציין delayMillis כדי לעכב את תחילת האנימציה.
val value by animateFloatAsState( targetValue = 1f, animationSpec = snap(delayMillis = 50), label = "snap spec" )
הגדרת פונקציית החלקה בהתאמה אישית
פעולות AnimationSpec שמבוססות על משך זמן (כמו tween או keyframes) משתמשות ב-Easing כדי לשנות את החלק של האנימציה. כך ערך האנימציה יכול להאיץ ולהאט, במקום לנוע בקצב קבוע. השבר הוא ערך בין 0 (התחלה) ל-1.0 (סוף) שמציין את הנקודה הנוכחית באנימציה.
הפונקציה Easing היא למעשה פונקציה שמקבלת ערך שבר בין 0 ל-1.0 ומחזירה מספר ממשי. הערך שמוחזר יכול להיות מחוץ לגבולות כדי לייצג חריגה מעל או מתחת לטווח. אפשר ליצור פונקציית האטה בהתאמה אישית, כמו בקוד שבהמשך.
val CustomEasing = Easing { fraction -> fraction * fraction } @Composable fun EasingUsage() { val value by animateFloatAsState( targetValue = 1f, animationSpec = tween( durationMillis = 300, easing = CustomEasing ), label = "custom easing" ) // …… }
ב-Compose יש כמה פונקציות Easing מובנות שמתאימות לרוב תרחישי השימוש.
במאמר מהירות – Material Design מוסבר בהרחבה על סוגי ההדרגה שמתאימים לתרחישים שונים.
FastOutSlowInEasingLinearOutSlowInEasingFastOutLinearInEasingLinearEasingCubicBezierEasing- לצפייה במודעות נוספות
הנפשה של סוגי נתונים מותאמים אישית על ידי המרה אל AnimationVector וממנו
רוב ממשקי ה-API של אנימציות ב-Compose תומכים ב-Float, Color, Dp ובסוגי נתונים בסיסיים אחרים כערכי אנימציה כברירת מחדל, אבל לפעמים צריך להוסיף אנימציה לסוגי נתונים אחרים, כולל סוגים בהתאמה אישית. במהלך האנימציה, כל ערך של אנימציה מיוצג בתור AnimationVector. הערך מומר ל-AnimationVector ולהפך על ידי TwoWayConverter תואם, כדי שמערכת האנימציה המרכזית תוכל לטפל בהם באופן אחיד. לדוגמה, Int מיוצג כ-AnimationVector1D שמכיל ערך float יחיד.
TwoWayConverter של Int נראה ככה:
val IntToVector: TwoWayConverter<Int, AnimationVector1D> = TwoWayConverter({ AnimationVector1D(it.toFloat()) }, { it.value.toInt() })
Color הוא למעשה קבוצה של 4 ערכים: אדום, ירוק, כחול ואלפא, ולכן Color מומר ל-AnimationVector4D שמכיל 4 ערכי float. כך, כל סוג נתונים שמשמש באנימציות מומר ל-AnimationVector1D, ל-AnimationVector2D, ל-AnimationVector3D או ל-AnimationVector4D, בהתאם לממדים שלו. כך אפשר להנפיש רכיבים שונים של האובייקט בנפרד, ולכל אחד מהם יש מעקב מהירות משלו. אפשר לגשת לממירים מובנים לסוגי נתונים בסיסיים באמצעות ממירים כמו Color.VectorConverter או Dp.VectorConverter.
כשרוצים להוסיף תמיכה בסוג נתונים חדש כערך אנימציה, אפשר ליצור TwoWayConverter משלכם ולספק אותו ל-API. לדוגמה, אתם יכולים להשתמש ב-animateValueAsState כדי להוסיף אנימציה לסוג הנתונים בהתאמה אישית, באופן הבא:
data class MySize(val width: Dp, val height: Dp) @Composable fun MyAnimation(targetSize: MySize) { val animSize: MySize by animateValueAsState( targetSize, TwoWayConverter( convertToVector = { size: MySize -> // Extract a float value from each of the `Dp` fields. AnimationVector2D(size.width.value, size.height.value) }, convertFromVector = { vector: AnimationVector2D -> MySize(vector.v1.dp, vector.v2.dp) } ), label = "size" ) }
הרשימה הבאה כוללת כמה VectorConverters מובנים:
Color.VectorConverterDp.VectorConverterOffset.VectorConverterInt.VectorConverterFloat.VectorConverterIntSize.VectorConverter
מומלץ בשבילכם
- הערה: טקסט הקישור מוצג כש-JavaScript מושבת
- אנימציות מבוססות-ערך
- פיתוח קוד איטרטיבי
- אנימציות ב-Compose