המשבצות תומכות בכמה גישות שונות לאנימציה, כולל:
- מעברים של טאטוא באמצעות אנימציות tween.
- אנימציות של החלקה והדהייה חלקות אל משבצת וממנה.
- אנימציות Lottie.
הצגת מעבר של טאטוא
כדי להציג מעבר חלק מערך אחד לערך אחר, אפשר להפעיל אנימציות tween לרכיב, כמו בדוגמה הבאה של קטע קוד:
private var startValue = 15f private var endValue = 105f private val animationDurationInMillis = 2000L // 2 seconds override fun onTileRequest(requestParams: RequestBuilders.TileRequest): ListenableFuture<Tile> { val circularProgressIndicator = CircularProgressIndicator.Builder() .setProgress( FloatProp.Builder(/* static value */ 0.25f) .setDynamicValue( // Or you can use some other dynamic object, for example // from the platform and then at the end of expression // add animate(). DynamicFloat.animate( startValue, endValue, AnimationSpec.Builder() .setAnimationParameters( AnimationParameters.Builder() .setDurationMillis(animationDurationInMillis) .build() ) .build(), ) ) .build() ) .build() return Futures.immediateFuture( Tile.Builder() .setResourcesVersion(RESOURCES_VERSION) .setTileTimeline(Timeline.fromLayoutElement(circularProgressIndicator)) .build() ) }
הגדרת כיוון הקשת
אם הרכיב מכיל קשת, יכול להיות שלא תרצו שקו הקשת או הטקסט יגדלו תמיד בכיוון הטקסט שמוגדר כברירת מחדל בשפה שבחר המשתמש. כדי לציין את כיוון הצמיחה של הקשת, משתמשים בממשקי ה-API ArcDirection
:
public override fun onTileRequest( requestParams: RequestBuilders.TileRequest ): ListenableFuture<Tile> { return Futures.immediateFuture( Tile.Builder() .setResourcesVersion(RESOURCES_VERSION) .setTileTimeline( Timeline.fromLayoutElement( EdgeContentLayout.Builder(deviceParameters) .setResponsiveContentInsetEnabled(true) .setEdgeContent( Arc.Builder() // Arc should always grow clockwise. .setArcDirection(LayoutElementBuilders.ARC_DIRECTION_CLOCKWISE) .addContent( ArcLine.Builder() // Set color, length, thickness, and more. // Arc should always grow clockwise. .setArcDirection( LayoutElementBuilders.ARC_DIRECTION_CLOCKWISE ) .build() ) .build() ) .build() ) ) .build() ) }
הצגת מעבר הדרגתי או החלקה
כדי להראות בצורה ברורה יותר שרכיב מופיע או נעלם במשבצת, או כדי להראות בצורה עדינה יותר שינוי הדרגתי בערך של משבצת, אפשר להשתמש באפקטים של הדהייה והחלקה באנימציות של המשבצות.
אם פריסת המשבצות מכילה רכיב שהערך שלו משתנה, המשבצת מציגה את אנימציית היציאה של הרכיב, ואז מעדכנת את הפריסה ומציגה את אנימציית הכניסה של הרכיב.
מעברים של כניסה ויציאה הדרגתית
בדוגמת הקוד הבאה אפשר לראות איך לבצע מעברים של הופעה הדרגתית והיעלמות הדרגתית באמצעות שיטות העזר מ-DefaultContentTransitions
. כדי להגדיר אובייקטים מותאמים אישית של FadeInTransition
ו-FadeOutTransition
, צריך להפעיל את setFadeIn()
ו-setFadeOut()
, בהתאמה, בשיטות להגדרת המעבר.
public override fun onTileRequest( requestParams: RequestBuilders.TileRequest ): ListenableFuture<Tile> { // Assumes that you've defined a custom helper method called // getTileTextToShow(). val tileText = getTileTextToShow() return Futures.immediateFuture( Tile.Builder() .setResourcesVersion(RESOURCES_VERSION) .setTileTimeline( Timeline.fromLayoutElement( Text.Builder(this, tileText) .setModifiers( Modifiers.Builder() .setContentUpdateAnimation( AnimatedVisibility.Builder() .setEnterTransition(DefaultContentTransitions.fadeIn()) .setExitTransition(DefaultContentTransitions.fadeOut()) .build() ) .build() ) .build() ) ) .build() ) }
מעברים בין שקפים
בדוגמה הבאה של קטע קוד אפשר לראות איך מבצעים מעברים של כניסה ויציאה באמצעות שיטות העזר מ-DefaultContentTransitions
. אפשר גם להגדיר אובייקטים מותאמים אישית של SlideInTransition
ו-SlideOutTransition
על ידי קריאה ל-setSlideIn()
ול-setSlideOut()
, בהתאמה, בשיטות להגדרת המעבר.
public override fun onTileRequest( requestParams: RequestBuilders.TileRequest ): ListenableFuture<Tile> { // Assumes that you've defined a custom helper method called // getTileTextToShow(). val tileText = getTileTextToShow() return Futures.immediateFuture( Tile.Builder() .setResourcesVersion(RESOURCES_VERSION) .setTileTimeline( Timeline.fromLayoutElement( Text.Builder(this, tileText) .setModifiers( Modifiers.Builder() .setContentUpdateAnimation( AnimatedVisibility.Builder() .setEnterTransition( DefaultContentTransitions.slideIn( ModifiersBuilders.SLIDE_DIRECTION_LEFT_TO_RIGHT ) ) .setExitTransition( DefaultContentTransitions.slideOut( ModifiersBuilders.SLIDE_DIRECTION_LEFT_TO_RIGHT ) ) .build() ) .build() ) .build() ) ) .build() ) }
הצגת טרנספורמציה
כדי להבליט רכיב או אזור ספציפיים במשבצת, אפשר להחיל עליהם כמה סוגים של טרנספורמציות, כולל: סיבוב, שינוי גודל והזזה.
הרבה ערכים של נקודה צפה שמשויכים לטרנספורמציות מקבלים ביטויים דינמיים, שמאפשרים להנפיש את הטרנספורמציות האלה.
סיבוב
כדי לבצע סיבוב עם כיוון השעון סביב נקודת ציר שאפשר להתאים אישית, משתמשים בקוד שדומה לקוד הבא:
return Futures.immediateFuture( Tile.Builder() .setResourcesVersion(RESOURCES_VERSION) .setTileTimeline( Timeline.fromLayoutElement( Text.Builder(this, someTileText) .setModifiers( Modifiers.Builder() .setTransformation( ModifiersBuilders.Transformation.Builder() // Set the pivot point 50 dp from the left edge // and 100 dp from the top edge of the screen. .setPivotX(dp(50f)) .setPivotY(dp(100f)) // Rotate the element 45 degrees clockwise. .setRotation(degrees(45f)) .build() ) .build() ) .build() ) ) .build() )
התאמה להיקף
כדי להגדיל או להקטין רכיב באמצעות גורמי קנה מידה אופקיים ואנכיים, משתמשים בקוד שדומה לקוד הבא:
return Futures.immediateFuture( Tile.Builder() .setResourcesVersion(RESOURCES_VERSION) .setTileTimeline( Timeline.fromLayoutElement( Text.Builder(this, someTileText) .setModifiers( Modifiers.Builder() .setTransformation( ModifiersBuilders.Transformation.Builder() // Set the pivot point 50 dp from the left edge // and 100 dp from the top edge of the screen. .setPivotX(dp(50f)) .setPivotY(dp(100f)) // Shrink the element by a scale factor // of 0.5 horizontally and 0.75 vertically. .setScaleX(FloatProp.Builder(0.5f).build()) .setScaleY(FloatProp.Builder(0.75f).build()) .build() ) .build() ) .build() ) ) .build() )
תרגום גיאומטרי
כדי להזיז רכיב במסך אופקית או אנכית במספר מסוים של פיקסלים בצפיפות (dp), משתמשים בקוד שדומה לקוד הבא:
return Futures.immediateFuture( Tile.Builder() .setResourcesVersion(RESOURCES_VERSION) .setTileTimeline( Timeline.fromLayoutElement( Text.Builder(this, someTileText) .setModifiers( Modifiers.Builder() .setTransformation( ModifiersBuilders.Transformation.Builder() // Translate (move) the element 60 dp to the right // and 80 dp down. .setTranslationX(dp(60f)) .setTranslationY(dp(80f)) .build() ) .build() ) .build() ) ) .build() )
אנימציות Lottie
במשבצות יש תמיכה בהפעלה של אנימציות Lottie, באמצעות תחביר שדומה לזה של תמונות:
class LottieAnimation : TileService() { val lottieResourceId = "lottie_animation" override fun onTileRequest(requestParams: RequestBuilders.TileRequest): ListenableFuture<Tile> { val layout = LayoutElementBuilders.Image.Builder() .setWidth(dp(150f)) .setHeight(dp(150f)) .setResourceId(lottieResourceId) .build() return Futures.immediateFuture( Tile.Builder() .setResourcesVersion(RESOURCES_VERSION) .setTileTimeline(Timeline.fromLayoutElement(layout)) .build() ) } override fun onTileResourcesRequest( requestParams: ResourcesRequest ): ListenableFuture<Resources> { val lottieImage = ResourceBuilders.ImageResource.Builder() .setAndroidLottieResourceByResId( ResourceBuilders.AndroidLottieResourceByResId.Builder(R.raw.lottie) .setStartTrigger(createOnVisibleTrigger()) .build() ) .build() return Futures.immediateFuture( Resources.Builder() .setVersion(requestParams.version) .addIdToImageMapping(lottieResourceId, lottieImage) .build() ) } }
כמה הערות חשובות:
- יש תמיכה רק בקבוצת משנה של קובצי Lottie. בודקים את התאימות באמצעות אחד מהכלי אימות הבאים:
- כלי תיקוף אונליין: https://skottie.skia.org/. בקטע 'דוח תאימות', הקובץ צריך לעבור את הבדיקות 'שגיאות במפרט', 'אזהרות במפרט' (בלי להתייחס למאפיינים נפוצים) ו'שגיאות בפרופיל צריכת חשמל נמוכה'.
- ספריית אימות של Rust: https://github.com/google/lottie-tools.
- הפעלת Lottie נתמכת על ידי רכיבי עיבוד של משבצות עם גרסה ראשית של לפחות
1
וגרסה משנית של לפחות500
. אם אנימציה מסוימת לא נתמכת, היא לא תוצג, אבל שאר האריח יוצג כצפוי. במקרה הצורך, אפשר לספק אפשרות חלופית, כמו תמונה סטטית.
לא כדאי להציג מידע חשוב באמצע אנימציה
יש כמה מצבים שבהם האנימציות מושבתות:
- יכול להיות שהמערכת תשבית את האנימציות בכל המשבצות.
- אפשר להנפיש רק 4 רכיבים בכל פעם במשבצת. אם מנסים להנפיש יותר מ-4 רכיבים בו-זמנית, לא כולם יציגו אנימציה.
במקרה שבו האנימציה מושבתת, הרכיבים הם סטטיים ומוצג בהם ערך הסיום של האנימציה. לכן, אל תסתמכו על התנהגות האנימציה, כמו משך הזמן שלה, כדי להציג מידע חשוב.