הרבה ממשקי API של אנימציה מקבלים בדרך כלל פרמטרים להתאמה אישית של ההתנהגות שלהם.
התאמה אישית של אנימציות באמצעות הפרמטר AnimationSpec
רוב ממשקי ה-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 מונפש על סמך ערכי תמונת המצב שצוינו בחותמות זמן שונות במהלך האנימציה. בכל רגע נתון, ערך האנימציה יהיה אינטרפולציה בין שני ערכים של מסגרות מפתח. לכל אחד מפריימי המפתח האלה אפשר לציין Easing כדי לקבוע את עקומת האינטרפולציה.
אפשר לציין את הערכים ב-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" )
אנימציה חלקה בין תמונות מפתח באמצעות keyframesWithSplines
כדי ליצור אנימציה שמתבססת על מעבר בין ערכים לאורך עקומה חלקה, אפשר להשתמש במפרטי אנימציה מסוג keyframesWithSplines במקום במפרטי אנימציה מסוג 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
|
keyframesWithSplines
|
|---|---|
כפי שאפשר לראות, נקודות המפתח מבוססות הספלין מציעות מעברים חלקים יותר בין הנקודות, כי הן משתמשות בעקומות בזייה כדי ליצור אנימציה חלקה בין הפריטים. המפרט הזה שימושי לאנימציה מוגדרת מראש. עם זאת, אם אתם עובדים עם נקודות שמונעות על ידי משתמשים, עדיף להשתמש בקפיצים כדי להשיג מעבר חלק דומה בין הנקודות, כי אפשר להפריע להם.
חזרה על אנימציה באמצעות 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" )
הגדרת פונקציית easing מותאמת אישית
פעולות מבוססות-משך (כמו tween או keyframes) משתמשות ב-Easing כדי להתאים את החלק של האנימציה.AnimationSpec כך ערך האנימציה יכול להאיץ ולהאט, במקום לנוע בקצב קבוע. השבר הוא ערך בין 0 (התחלה) ל-1.0 (סוף) שמציין את הנקודה הנוכחית באנימציה.
ההאצה היא למעשה פונקציה שמקבלת ערך שבר בין 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.
FastOutSlowInEasingLinearOutSlowInEasingFastOutLinearEasingLinearEasingCubicBezierEasing- מידע נוסף
הנפשה של סוגי נתונים מותאמים אישית על ידי המרה אל AnimationVector וממנו
רוב ממשקי ה-API של אנימציות ב-Compose תומכים ב-Float, Color, Dp ובסוגי נתונים בסיסיים אחרים כערכי אנימציה כברירת מחדל, אבל לפעמים צריך להנפיש סוגי נתונים אחרים, כולל סוגי נתונים מותאמים אישית. במהלך האנימציה, כל ערך אנימציה מיוצג כ-AnimationVector. הערך מומר ל-AnimationVector ולהפך על ידי TwoWayConverter תואם, כדי שמערכת האנימציה המרכזית תוכל לטפל בהם באופן אחיד. לדוגמה, Int מיוצג כ-AnimationVector1D שמכיל ערך נקודה צפה יחיד.
TwoWayConverter for 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 מושבת
- אנימציות מבוססות-ערך
- פיתוח איטרטיבי של קוד {:#iterative-code-dev }
- אנימציות ב-Compose