הרבה ממשקי 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
שמתאימות לרוב תרחישי השימוש.
מידע נוסף על סוגי ה-Easing שמתאימים לתרחישים שונים זמין במאמר Speed - Material Design.
FastOutSlowInEasing
LinearOutSlowInEasing
FastOutLinearEasing
LinearEasing
CubicBezierEasing
- מידע נוסף
הנפשת סוגי נתונים מותאמים אישית על ידי המרה אל 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" ) }
הרשימה הבאה כוללת כמה VectorConverter
s מובנים:
Color.VectorConverter
Dp.VectorConverter
Offset.VectorConverter
Int.VectorConverter
Float.VectorConverter
IntSize.VectorConverter
מומלץ עבורך
- הערה: טקסט הקישור מוצג כש-JavaScript מושבת
- אנימציות מבוססות-ערך
- פיתוח איטרטיבי של קוד {:#iterative-code-dev }
- אנימציות בכתיבה