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