Animazioni riquadri

I riquadri supportano diversi approcci di animazione, tra cui:

Mostrare una transizione di scorrimento

Per mostrare una transizione graduale da un valore all'altro, puoi attivare le animazioni tween per un elemento, come mostrato nello snippet di codice seguente:

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()
    )
}

Imposta la direzione dell'arco

Se il riquadro contiene un arco, potresti non volere che la linea o il testo dell'arco aumentino sempre nella direzione del testo predefinita per la lingua scelta dall'utente. Per specificare una direzione di crescita dell'arco, utilizza le 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()
    )
}

Mostrare una dissolvenza o una transizione fluida

Per indicare più chiaramente che un elemento appare o scompare in un riquadro o per mostrare in modo più sottile una variazione graduale nel valore di un riquadro, utilizza gli effetti di dissolvenza e scorrimento nelle animazioni dei riquadri.

Se un layout a riquadri contiene un elemento il cui valore cambia, il riquadro mostra l'animazione di uscita dell'elemento, quindi aggiorna il layout e mostra l'animazione di entrata dell'elemento.

Transizioni con dissolvenza

Il seguente snippet di codice mostra come eseguire transizioni di dissolvenza in entrata e in uscita utilizzando i metodi helper di DefaultContentTransitions. Per definire oggetti FadeInTransition e FadeOutTransition personalizzati, chiama setFadeIn() e setFadeOut(), rispettivamente, nei metodi setter di transizione.

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()
    )
}

Transizioni tra le slide

Questo altro snippet di codice mostra come eseguire transizioni di scorrimento verso l'interno e verso l'esterno utilizzando i metodi helper di DefaultContentTransitions. Puoi anche definire oggetti SlideInTransition e SlideOutTransition personalizzati chiamando rispettivamente setSlideIn() e setSlideOut() nei metodi setter di transizione.

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()
    )
}

Mostrare una trasformazione

Per richiamare l'attenzione su un elemento o un'area specifica in un riquadro, puoi applicare diversi tipi di trasformazioni, tra cui rotazione, ridimensionamento e traslazione.

Molti valori in virgola mobile associati alle trasformazioni accettano espressioni dinamiche, che ti consentono di animare queste trasformazioni.

Rotazione

Per eseguire una rotazione in senso orario attorno a un punto di rotazione personalizzabile, utilizza un codice simile al seguente:

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()
)

Scalabilità

Per ingrandire o ridurre un elemento in base ai fattori di scalabilità orizzontale e verticale, utilizza un codice simile al seguente:

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()
)

Traslazione geometrica

Per spostare un elemento di un numero specifico di pixel di densità (dp) sullo schermo in orizzontale o in verticale, utilizza un codice simile al seguente:

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()
)

Animazioni Lottie

I riquadri supportano la riproduzione di animazioni Lottie, utilizzando una sintassi simile a quella delle immagini:

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()
        )
    }
}

Alcuni punti da notare:

  • È supportato solo un sottoinsieme di file Lottie. Verifica la compatibilità utilizzando uno dei seguenti strumenti di convalida:
    • Un validatore online: https://skottie.skia.org/. Nella sezione "Report di compatibilità", il file deve superare i test "Errori di specifica", "Avvisi di specifica" (con le proprietà comuni ignorate) e "Errori del profilo a basso consumo energetico".
    • Una libreria di convalida Rust: https://github.com/google/lottie-tools.
  • La riproduzione di Lottie è supportata dai renderer dei riquadri con una versione principale almeno 1 e una versione secondaria almeno 500. Se una determinata animazione non è supportata, non viene visualizzata, ma il resto del riquadro viene visualizzato come previsto. Se necessario, puoi fornire un'opzione di riserva, ad esempio un' immagine statica.

Non mostrare informazioni importanti al centro di un'animazione

Esistono diverse situazioni in cui le animazioni sono disattivate:

  • Il rendering dei riquadri del sistema potrebbe disattivare le animazioni per tutti i riquadri.
  • Un riquadro può animare solo 4 elementi alla volta. Se provi ad animare più di 4 elementi contemporaneamente, non tutti mostreranno un'animazione.

Nel caso in cui un'animazione sia disattivata, gli elementi sono statici e mostrano il valore finale dell'animazione. Per questo motivo, non fare affidamento sul comportamento dell'animazione, ad esempio sulla sua durata, per mostrare informazioni importanti.