Вы можете анимировать плитки несколькими различными способами, в том числе следующими:
- Сдвигайте переходы с помощью анимации анимации.
- Плавное затухание и скольжение анимации на плитке и за ее пределами.
Показать плавный переход
Чтобы отобразить плавный переход от одного значения к другому, вы можете включить анимацию анимации для элемента, как показано в следующем фрагменте кода:
private val defaultValue = 0f
private var startValue = 15f
private var endValue = 105f
private val animationDurationInMillis = 2000f // 2 seconds
override fun onTileRequest(requestParams: TileRequest) =
Futures.immediateFuture(
// Add timeline and layout containers. CircularProgressIndicator is an
// inner element of those containers.
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()
// Finish building all elements that contain CircularProgressIndicator.
)
private float defaultValue = 0f;
private float startValue = 15f;
private float endValue = 105f;
private float animationDurationInMillis = 2000f; // 2 seconds
@Override
protected ListenableFuture<Tile> onTileRequest(
@NonNull TileRequest requestParams
) {
return Futures.immediateFuture(
// Add timeline and layout containers. CircularProgressIndicator is an
// inner element of those containers.
new CircularProgressIndicator.Builder()
.setProgress(
new 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,
new AnimationSpec.Builder()
.setAnimationParameters(
new AnimationParameters.Builder()
.setDurationMillis(animationDurationInMillis)
.build()
).build()
)
).build()
).build()
// Finish building all elements that contain CircularProgressIndicator.
);
}
Установить направление дуги
Если ваша плитка содержит дугу, возможно, вы не захотите, чтобы линия дуги или текст всегда росли в направлении текста по умолчанию для выбранного пользователем языка. Чтобы указать направление роста дуги, используйте API ArcDirection
:
@OptIn(ProtoLayoutExperimental::class)
public override fun onTileRequest(
requestParams: RequestBuilders.TileRequest
): ListenableFuture<Tile> {
return Futures.immediateFuture(Tile.Builder()
.setResourcesVersion(RESOURCES_VERSION)
.setTileTimeline(Timeline.fromLayoutElement(
EdgeContentLayout.Builder(deviceParameters)
.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()
)
}
@OptIn(markerClass = ProtoLayoutExperimental.class)
@NonNull
@Override
protected ListenableFuture<Tile> onTileRequest(
@NonNull RequestBuilders.TileRequest requestParams
) {
return Futures.immediateFuture(new Tile.Builder()
.setResourcesVersion(RESOURCES_VERSION)
.setTileTimeline(Timeline.fromLayoutElement(
new EdgeContentLayout.Builder(deviceParameters)
.setEdgeContent(
new Arc.Builder()
// Arc should always grow clockwise.
.setArcDirection(LayoutElementBuilders.ARC_DIRECTION_CLOCKWISE)
.addContent(
new 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()
соответственно в методах установки перехода.
@OptIn(ProtoLayoutExperimental::class)
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(
ModifiersBuilders.Modifiers.Builder()
.setContentUpdateAnimation(AnimatedVisibility.Builder()
.setEnterTransition(
DefaultContentTransitions.fadeIn())
.setExitTransition(
DefaultContentTransitions.fadeOut()
).build())
).build())
).build()
)
}
@OptIn(markerClass = ProtoLayoutExperimental.class)
@NonNull
@Override
protected ListenableFuture<Tile> onTileRequest(
@NonNull RequestBuilders.TileRequest requestParams
) {
// Assumes that you've defined a custom helper method called
// getTileTextToShow().
String tileText = getTileTextToShow();
return Futures.immediateFuture(new Tile.Builder()
.setResourcesVersion(RESOURCES_VERSION)
.setTileTimeline(Timeline.fromLayoutElement(
new Text.Builder(this, tileText)
.setModifiers(
new ModifiersBuilders.Modifiers.Builder()
.setContentUpdateAnimation(new AnimatedVisibility.Builder()
.setEnterTransition(
DefaultContentTransitions.fadeIn())
.setExitTransition(
DefaultContentTransitions.fadeOut())
.build())
.build()))
.build()
);
}
Переходы между слайдами
Этот другой фрагмент кода демонстрирует, как выполнять переходы с выдвижением и выдвижением с помощью вспомогательных методов из DefaultContentTransitions
. Вы также можете определить собственные объекты SlideInTransition
и SlideOutTransition
вызвав setSlideIn()
и setSlideOut()
соответственно в методах установки перехода.
@OptIn(ProtoLayoutExperimental::class)
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(
SLIDE_DIRECTION_LEFT_TO_RIGHT)
).setExitTransition(
DefaultContentTransitions.slideOut(
SLIDE_DIRECTION_LEFT_TO_RIGHT)
).build()
).build()
).build()
)).build()
)
}
@OptIn(markerClass = ProtoLayoutExperimental.class)
@NonNull
@Override
protected ListenableFuture<Tile> onTileRequest(
@NonNull RequestBuilders.TileRequest requestParams
) {
// Assumes that you've defined a custom helper method called
// getTileTextToShow().
String tileText = getTileTextToShow();
return Futures.immediateFuture(Tile.Builder()
.setResourcesVersion(RESOURCES_VERSION)
.setTileTimeline(Timeline.fromLayoutElement(
new Text.Builder(this, tileText)
.setModifiers(
new Modifiers.Builder()
.setContentUpdateAnimation(
new AnimatedVisibility.Builder()
.setEnterTransition(
DefaultContentTransitions.slideIn(
SLIDE_DIRECTION_LEFT_TO_RIGHT))
.setExitTransition(
DefaultContentTransitions.slideOut(
SLIDE_DIRECTION_LEFT_TO_RIGHT))
.build())
.build())
.build()))
.build()
);
}
Показать трансформацию
Чтобы привлечь внимание к определенному элементу или области плитки, вы можете применить к нему несколько типов преобразований, в том числе: вращение, масштабирование и перемещение.
Многие значения с плавающей запятой, связанные с преобразованиями, принимают динамические выражения , которые позволяют анимировать эти преобразования.
Вращение
Чтобы выполнить вращение по часовой стрелке вокруг настраиваемой точки поворота, используйте код, аналогичный следующему:
// Last line in your onTileRequest() method implementation.
return Futures.immediateFuture(Tile.Builder()
.setResourcesVersion(RESOURCES_VERSION)
.setTileTimeline(Timeline.fromLayoutElement(
Text.Builder(this, someTileText)
.setModifiers(
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(50))
.setPivotY(dp(100))
// Rotate the element 45 degrees clockwise.
.setRotation(
degrees(45f)
).build()
).build())
).build()
)
// Last line in your onTileRequest() method implementation.
return Futres.immediateFuture(new Tile.Builder()
.setResourcesVersion(RESOURCES_VERSION)
.setTileTimeline(Timeline.fromLayoutElement(
new Text.Builder(this, someTileText)
.setModifiers(
new 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(50))
.setPivotY(dp(100))
// Rotate the element 45 degrees clockwise.
.setRotation(
degrees(45f))
.build())
.build()))
.build()
);
Масштабирование
Чтобы увеличить или уменьшить элемент с помощью коэффициентов горизонтального и вертикального масштабирования, используйте код, аналогичный следующему:
// Last line in your onTileRequest() method implementation.
return Futures.immediateFuture(Tile.Builder()
.setResourcesVersion(RESOURCES_VERSION)
.setTileTimeline(Timeline.fromLayoutElement(
Text.Builder(this, someTileText)
.setModifiers(
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(50))
.setPivotY(dp(100))
// Shrink the element by a scale factor
// of 0.5 horizontally and 0.75 vertically.
.setScaleX(TypeBuilders.FloatProp.Builder(0.5f)
.build())
.setScaleY(TypeBuilders.FloatProp.Builder(0.75f)
.build()
).build()
).build())
).build()
)
// Last line in your onTileRequest() method implementation.
return Futres.immediateFuture(new Tile.Builder()
.setResourcesVersion(RESOURCES_VERSION)
.setTileTimeline(Timeline.fromLayoutElement(
new Text.Builder(this, someTileText)
.setModifiers(
new 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(50))
.setPivotY(dp(100))
// Shrink the element by a scale factor
// of 0.5 horizontally and 0.75 vertically.
.setScaleX(new TypeBuilders.FloatProp.Builder(0.5f)
.build())
.setScaleY(new TypeBuilders.FloatProp.Builder(0.75f)
.build())
.build())
.build()))
.build()
);
Геометрический перевод
Чтобы переместить элемент на определенное количество пикселей плотности (dp) по экрану по горизонтали или вертикали, используйте код, аналогичный следующему:
// Last line in your onTileRequest() method implementation.
return Futures.immediateFuture(Tile.Builder()
.setResourcesVersion(RESOURCES_VERSION)
.setTileTimeline(Timeline.fromLayoutElement(
Text.Builder(this, someTileText)
.setModifiers(
ModifiersBuilders.Transformation.Builder()
// Translate (move) the element 60 dp to the right
// and 80 dp down.
.setTranslationX(dp(60))
.setTranslationY(dp(80))
.build()
).build())
).build()
)
// Last line in your onTileRequest() method implementation.
return Futres.immediateFuture(new Tile.Builder()
.setResourcesVersion(RESOURCES_VERSION)
.setTileTimeline(Timeline.fromLayoutElement(
new Text.Builder(this, someTileText)
.setModifiers(
new ModifiersBuilders.Transformation.Builder()
// Translate (move) the element 60 dp to the right
// and 80 dp down.
.setTranslationX(dp(60))
.setTranslationY(dp(80))
.build())
.build()))
.build()
);
Не показывайте важную информацию в середине анимации
Есть несколько ситуаций, в которых анимация отключена:
- Система рендеринга плиток может отключить анимацию для всех плиток.
- Плитка может анимировать только 4 элемента одновременно. Если вы попытаетесь анимировать более 4 элементов одновременно, не все из них отобразят анимацию.
В случае, когда анимация отключена, элементы являются статическими и показывают конечное значение анимации. По этой причине не полагайтесь на поведение анимации, например ее продолжительность, для отображения важной информации.