Плитки поддерживают несколько различных подходов к анимации, включая следующие:
- Переходы между кадрами с использованием анимации переходов .
- Плавная анимация появления и исчезновения плитки.
- Анимации Лотти .
Показать переход развертки
Чтобы продемонстрировать плавный переход от одного значения к другому, можно включить анимацию переходов для элемента, как показано в следующем фрагменте кода:
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() )
Анимации Лотти
Tiles поддерживает воспроизведение анимаций 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 элементов одновременно, не все из них будут анимированы.
Если анимация отключена, элементы статичны и отображают конечное значение анимации. Поэтому не полагайтесь на поведение анимации, например на её продолжительность, для отображения важной информации.