רבים מממשקי ה-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
.
איור 1. הגדרת יחסי דעיכה שונים של קפיצים.
stiffness
מגדיר את המהירות שבה האביב צריך לנוע לעבר ערך הסיום. ערך ברירת המחדל הוא Spring.StiffnessMedium
.
איור 2. הגדרת קשיחות שונה של קפיץ
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
.
איור 3. הגדרת מפרט 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
מפעיל אנימציה על סמך ערכי קובץ snapshot שצוינו בחותמות זמן שונות במהלך משך האנימציה. בכל רגע נתון, ערך האנימציה יתבצע אינטרפולציה בין שני ערכים של נקודות מפתח. לכל אחד מ-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" )
איך חוזרים על אנימציה באמצעות 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
שמבוססות על משך זמן (כמו tween
או keyframes
) משתמשות ב-Easing
כדי לשנות את החלק של האנימציה. כך הערך שמופיע בהנפשה יכול לנוע במהירות גבוהה יותר או איטית יותר, במקום לנוע בקצב קבוע. Fraction הוא ערך בין 0 (התחלה) ל-1.0 (סוף) שמייצג את הנקודה הנוכחית באנימציה.
העברה חלקה היא למעשה פונקציה שמקבלת ערך שבר בין 0 ל-1.0 ומחזירה ערך של float. הערך המוחזר יכול להיות מחוץ לגבול כדי לייצג חריגה מעל או מתחת לערך היעד. אפשר ליצור עקומת Easing בהתאמה אישית כמו הקוד הבא.
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) המתאימה לתרחיש שלכם, תוכלו לעיין במאמר מהירות – Material Design.
FastOutSlowInEasing
LinearOutSlowInEasing
FastOutLinearEasing
LinearEasing
CubicBezierEasing
- מידע נוסף
אנימציה של סוגי נתונים מותאמים אישית על ידי המרה אל 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" ) }
הרשימה הבאה כוללת כמה VectorConverter
מובנים:
Color.VectorConverter
Dp.VectorConverter
Offset.VectorConverter
Int.VectorConverter
Float.VectorConverter
IntSize.VectorConverter
מומלץ עבורך
- הערה: טקסט הקישור מוצג כש-JavaScript מושבת
- אנימציות מבוססות-ערך
- פיתוח קוד איטרטיבי {:#iterative-code-dev }
- אנימציות ב-Compose