Introduzione a MotionLayout Android

MotionLayout Android è oggi uno degli strumenti più potenti per creare animazioni Android Java moderne, fluide e completamente dichiarative. A differenza degli approcci tradizionali basati su ObjectAnimator o ValueAnimator, con MotionLayout puoi definire gran parte della logica di movimento direttamente nei file XML, separando in modo pulito la parte grafica dal codice dell’attività.

In questa guida pratica vedrai come configurare un MotionScene Android, come collegarlo al layout della tua activity e come usare ConstraintSet, Transition, KeyFrameSet e OnSwipe per ottenere animazioni complesse controllate sia da gesture sia da eventi di click. Gli esempi sono pensati per essere copiati e incollati direttamente nei tuoi progetti con Android Studio, usando Java come linguaggio principale.

Questa guida completa su MotionLayout Android ti permetterà di scoprire come creare animazioni fluide e reattive direttamente nei layout XML della tua app, gestendo transizioni complesse tra ConstraintSet senza dover scrivere logiche di animazione complicate. Vedrai come utilizzare MotionScene, Transition e KeyFrameSet per dare vita alla tua interfaccia, mentre gli esempi pratici, sviluppati con Java e Android Studio, potrai integrarli subito nei tuoi progetti reali.


MotionLayout Android animazioni con ConstraintLayout e MotionScene

Cos’è MotionLayout Android

Una sottoclasse di ConstraintLayout, MotionLayout ti permette di definire le animazioni direttamente nel layout XML. Questo approccio riduce drasticamente la necessità di codice Java o Kotlin, permettendoti di gestire quasi tutto via XML. In questo modo, scorrimenti, tocchi, rotazioni e cambi di scala vengono descritti in un file XML separato chiamato MotionScene.

Componenti principali di MotionLayout Android

  • <MotionScene>: rappresenta, in altre parole, il file XML che descrive tutta l’animazione e che colleghi al layout con l’attributo app:layoutDescription.
  • <ConstraintSet>: serve a definire l’aspetto iniziale (start) e finale (end) dell’animazione: posizione, dimensione e rotazione di ogni view.
  • <Transition>: questo elemento collega due ConstraintSet e imposta durata e tipo di interpolazione dell’animazione.
  • <KeyFrameSet>: con questo, inserisci stati intermedi nell’animazione per ottenere movimenti più complessi, ad esempio una rotazione a metà percorso.
  • <OnSwipe>: qui l’animazione viene avviata quando l’utente esegue un gesto di swipe.

Esempio Android: animazione swipe con MotionLayout

In questo esempio di MotionLayout Android, una view si muove da sinistra a destra con una rotazione di 360°. Durante il movimento, nello specifico, ruota e cambia scala. Questi passaggi sono descritti in un KeyFrameSet, che consente di ottenere movimenti più complessi e fluidi.

res/layout/activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.motion.widget.MotionLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    app:layoutDescription="@layout/activity_scene"
    tools:context=".MainActivity">

    <View
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/view"
        android:background="#FFBB86" />

</androidx.constraintlayout.motion.widget.MotionLayout>

res/layout/activity_scene.xml (MotionScene)

<MotionScene xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:motion="http://schemas.android.com/apk/res-auto">

    <Transition
        motion:constraintSetStart="@+id/start"
        motion:constraintSetEnd="@+id/end"
        motion:duration="1000"
        motion:motionInterpolator="easeIn">

        <OnSwipe
            motion:dragDirection="dragRight"
            motion:touchAnchorId="@+id/view"
            motion:touchAnchorSide="right" />

        <KeyFrameSet>
            <KeyAttribute
                android:rotation="180"
                android:scaleX="3"
                android:scaleY="-3"
                motion:framePosition="20"
                motion:motionTarget="@id/view" />
            <KeyPosition
                motion:framePosition="20"
                motion:keyPositionType="deltaRelative"
                motion:motionTarget="@id/view"
                motion:percentY="-0.5" />
        </KeyFrameSet>

    </Transition>

    <!-- Stato iniziale: view a sinistra -->
    <ConstraintSet android:id="@+id/start">
        <Constraint
            android:id="@+id/view"
            android:layout_width="50dp"
            android:layout_height="50dp"
            motion:layout_constraintBottom_toBottomOf="parent"
            motion:layout_constraintStart_toStartOf="parent"
            motion:layout_constraintTop_toTopOf="parent" />
    </ConstraintSet>

    <!-- Stato finale: view a destra -->
    <ConstraintSet android:id="@+id/end">
        <Constraint
            android:id="@+id/view"
            android:layout_width="50dp"
            android:layout_height="50dp"
            motion:layout_constraintBottom_toBottomOf="parent"
            motion:layout_constraintEnd_toEndOf="parent"
            motion:layout_constraintTop_toTopOf="parent" />
    </ConstraintSet>

</MotionScene>

Spiegazione dell’esempio

  • Anzitutto, il layout principale usa MotionLayout al posto di ConstraintLayout e collega il file MotionScene tramite l’attributo app:layoutDescription.
  • Inoltre, la Transition imposta durata (1000 ms), interpolazione (easeIn) e trigger: uno swipe verso destra (dragRight) sull’elemento @id/view.
  • Di conseguenza, il KeyFrameSet aggiunge uno stato intermedio al 20% del percorso: la view ruota di 180°, viene scalata di 3x e si sposta verso l’alto.
  • Infine, i due ConstraintSet (start ed end) definiscono rispettivamente la posizione iniziale (sinistra) e finale (destra) della view.

Dipendenza Gradle

Nel file build.gradle aggiungi la seguente dipendenza:

implementation 'androidx.constraintlayout:constraintlayout:2.1.4'

La libreria constraintlayout include MotionLayout a partire dalla versione 2.0, quindi non avrai bisogno di dipendenze aggiuntive oltre a quella base.

Animazione al click di un bottone con MotionLayout Android

Oltre alle gesture di swipe, puoi usare MotionLayout Android per avviare un'animazione al click di un bottone. In questo esempio useremo Java per chiamare i metodi transitionToEnd() e transitionToStart() sul layout, mentre tutta la logica di transizione viene definita nel file MotionScene Android.

res/layout/activity_main.xml (MotionLayout + Button)

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.motion.widget.MotionLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/motionLayout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    app:layoutDescription="@xml/activity_main_scene">

    <Button
        android:id="@+id/btnAnimate"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Anima"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/viewBox" />

    <View
        android:id="@+id/viewBox"
        android:layout_width="80dp"
        android:layout_height="80dp"
        android:background="#FFBB86"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toEndOf="parent" />

</androidx.constraintlayout.motion.widget.MotionLayout>

res/xml/activity_main_scene.xml (MotionScene)

<MotionScene xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:motion="http://schemas.android.com/apk/res-auto">

    <Transition
        android:id="@+id/transition_click"
        motion:constraintSetStart="@+id/start"
        motion:constraintSetEnd="@+id/end"
        motion:duration="600">
    </Transition>

    <ConstraintSet android:id="@+id/start">
        <Constraint
            android:id="@+id/viewBox"
            android:layout_width="80dp"
            android:layout_height="80dp"
            motion:layout_constraintTop_toTopOf="parent"
            motion:layout_constraintBottom_toBottomOf="parent"
            motion:layout_constraintStart_toStartOf="parent"
            motion:layout_constraintEnd_toEndOf="parent" />
    </ConstraintSet>

    <ConstraintSet android:id="@+id/end">
        <Constraint
            android:id="@+id/viewBox"
            android:layout_width="120dp"
            android:layout_height="120dp"
            android:rotation="360"
            motion:layout_constraintBottom_toBottomOf="parent"
            motion:layout_constraintEnd_toEndOf="parent"
            motion:layout_constraintTop_toTopOf="parent" />
    </ConstraintSet>

</MotionScene>

MainActivity.java (animazione al click)

public class MainActivity extends AppCompatActivity {

    private MotionLayout motionLayout;
    private Button btnAnimate;
    private boolean isEnd = false;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        motionLayout = findViewById(R.id.motionLayout);
        btnAnimate = findViewById(R.id.btnAnimate);

        btnAnimate.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (!isEnd) {
                    motionLayout.transitionToEnd();
                } else {
                    motionLayout.transitionToStart();
                }
                isEnd = !isEnd;
            }
        });
    }
}

Transizioni con KeyFrame in MotionLayout Android

Le animazioni Android Java diventano particolarmente potenti quando combini MotionLayout con i KeyFrame. All'interno di un KeyFrameSet puoi utilizzare KeyPosition per controllare la posizione di un elemento lungo il percorso e KeyAttribute per modificare proprietà come scala, rotazione, alpha e altro durante l'animazione.

Esempio di KeyPosition

<KeyFrameSet>
    <KeyPosition
        motion:motionTarget="@id/viewBox"
        motion:framePosition="50"
        motion:keyPositionType="pathRelative"
        motion:percentX="0.8"
        motion:percentY="0.2" />
</KeyFrameSet>

In questo esempio KeyPosition sposta la view al 50% della transizione, posizionandola all'80% del percorso orizzontale e al 20% di quello verticale rispetto al path definito tra i due ConstraintSet.

Esempio di KeyAttribute

<KeyFrameSet>
    <KeyAttribute
        motion:motionTarget="@id/viewBox"
        motion:framePosition="30"
        android:rotation="45"
        android:alpha="0.5" />

    <KeyAttribute
        motion:motionTarget="@id/viewBox"
        motion:framePosition="70"
        android:rotation="-45"
        android:scaleX="1.5"
        android:scaleY="1.5" />
</KeyFrameSet>

Con KeyAttribute controlli l'aspetto dell'elemento in punti specifici della transizione. Nel codice precedente la view ruota e cambia alpha al 30% dell'animazione, quindi modifica rotazione e scala al 70%, ottenendo un effetto molto più ricco rispetto a una semplice interpolazione lineare.

MotionLayout vs ObjectAnimator vs ValueAnimator

Se hai già usato ObjectAnimator o ValueAnimator per creare animazioni Android in Java, ti sarai chiesto quando conviene passare a MotionLayout Android. La tabella seguente mette a confronto i tre approcci principali.

CaratteristicaMotionLayoutObjectAnimatorValueAnimator
Dichiarazione animazioniPer lo più in XML (MotionScene), poco codice JavaInteramente in codice Java/KotlinInteramente in codice Java/Kotlin
Gestione layout complessiIntegrato con ConstraintLayout, supporta transizioni tra più ConstraintSetLimitato a singole property su singole viewDevi aggiornare manualmente le property nella callback
KeyFrame e stati intermediSupporto nativo con KeyPosition, KeyAttribute, KeyCycleGestione manuale o concatenazione di animazioniGestione manuale nella callback onAnimationUpdate
Gesture e interazioniSupporto integrato con OnSwipe, OnClick, ecc.Richiede codice extra per gestire gesture e sincronizzazioneRichiede codice extra per gestire gesture e sincronizzazione
Curva di apprendimentoMedia/Alta (MotionScene, ConstraintSet, KeyFrame)BassaBassa/Media

Errori comuni con MotionLayout e come risolverli

  • MotionScene non collegato al layout: se l'animazione non parte, verifica di aver impostato correttamente app:layoutDescription="@xml/tuo_scene" nel tag MotionLayout. Senza questo attributo il file MotionScene Android non viene caricato.
  • ID non corrispondenti tra layout e MotionScene: gli android:id usati nei Constraint del MotionScene devono combaciare con quelli definiti nel layout. Se sbagli ID (ad esempio @+id/box contro @+id/viewBox), MotionLayout ignorerà il constraint.
  • ConstraintSet incompleti: se una view "scompare" o si comporta in modo strano, assicurati che sia definita sia nel ConstraintSet start che in quello end. View presenti solo in uno dei due stati possono causare animazioni imprevedibili.
  • Errore di durata o interpolazione: valori estremi di motion:duration o interpolatori sbagliati possono dare l'impressione che l'animazione non funzioni. Prova con una durata intermedia (500–800 ms) e un interpolatore standard come easeInOut per il debug.

FAQ su MotionLayout Android

Cos'è MotionLayout Android?

MotionLayout Android è un layout avanzato basato su ConstraintLayout che permette di descrivere animazioni e transizioni complesse direttamente in XML tramite un file MotionScene. È pensato per coordinare layout e animazioni in modo dichiarativo, riducendo la quantità di codice Java necessaria.

MotionLayout funziona con ConstraintLayout?

Sì. MotionLayout è una sottoclasse di ConstraintLayout, quindi eredita tutte le sue funzionalità di posizionamento e vincoli tra view. In pratica puoi considerarlo come un ConstraintLayout con supporto integrato per animazioni dichiarative basate su ConstraintSet e Transition.

Come creare animazioni con MotionLayout in Java?

Per creare animazioni con MotionLayout in Java devi: 1) usare MotionLayout nel file di layout, 2) collegare un file MotionScene tramite app:layoutDescription, 3) definire ConstraintSet e Transition nel MotionScene, 4) dal codice Java richiamare metodi come transitionToEnd(), transitionToStart() o impostare listener per reagire agli stati della transizione.

Posso usare MotionLayout con Kotlin invece che con Java?

Sì, MotionLayout è indipendente dal linguaggio usato nel codice dell'app. In questa guida gli esempi sono in Java, ma puoi usare le stesse definizioni XML di MotionScene Android anche in progetti scritti in Kotlin, cambiando solo il codice dell'activity o del fragment.

Quando conviene usare MotionLayout invece di ObjectAnimator?

Conviene usare MotionLayout Android quando devi gestire animazioni di layout complesse, sincronizzate tra più view, magari controllate da swipe o scroll. ObjectAnimator resta più adatto a semplici animazioni su una singola proprietà (ad esempio ruotare un'icona) quando non ti serve un controllo fine su stati intermedi, gesture e vincoli di layout.


Guide correlate