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.

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’attributoapp: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 dueConstraintSete 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
MotionLayoutal posto diConstraintLayoute collega il file MotionScene tramite l’attributoapp:layoutDescription. - Inoltre, la
Transitionimposta durata (1000 ms), interpolazione (easeIn) e trigger: uno swipe verso destra (dragRight) sull’elemento@id/view. - Di conseguenza, il
KeyFrameSetaggiunge 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(startedend) 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.
| Caratteristica | MotionLayout | ObjectAnimator | ValueAnimator |
|---|---|---|---|
| Dichiarazione animazioni | Per lo più in XML (MotionScene), poco codice Java | Interamente in codice Java/Kotlin | Interamente in codice Java/Kotlin |
| Gestione layout complessi | Integrato con ConstraintLayout, supporta transizioni tra più ConstraintSet | Limitato a singole property su singole view | Devi aggiornare manualmente le property nella callback |
| KeyFrame e stati intermedi | Supporto nativo con KeyPosition, KeyAttribute, KeyCycle | Gestione manuale o concatenazione di animazioni | Gestione manuale nella callback onAnimationUpdate |
| Gesture e interazioni | Supporto integrato con OnSwipe, OnClick, ecc. | Richiede codice extra per gestire gesture e sincronizzazione | Richiede codice extra per gestire gesture e sincronizzazione |
| Curva di apprendimento | Media/Alta (MotionScene, ConstraintSet, KeyFrame) | Bassa | Bassa/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 tagMotionLayout. Senza questo attributo il file MotionScene Android non viene caricato. - ID non corrispondenti tra layout e MotionScene: gli
android:idusati neiConstraintdel MotionScene devono combaciare con quelli definiti nel layout. Se sbagli ID (ad esempio@+id/boxcontro@+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 startche in quelloend. View presenti solo in uno dei due stati possono causare animazioni imprevedibili. - Errore di durata o interpolazione: valori estremi di
motion:durationo interpolatori sbagliati possono dare l'impressione che l'animazione non funzioni. Prova con una durata intermedia (500–800 ms) e un interpolatore standard comeeaseInOutper 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.
Articoli correlati
Guide correlate
- Per gestire liste complesse con animazioni fluide dai un'occhiata alla guida su RecyclerView Android.
- Se ti serve organizzare i vincoli in modo avanzato puoi approfondire ConstraintLayout Android.
- Per creare barre superiori moderne e personalizzate vedi la guida su Toolbar Android.
- Se vuoi aggiungere un menu laterale a scomparsa consulta la guida a NavigationDrawer Android.
- Per implementare il gesto di aggiornamento con swipe verso il basso scopri come usare SwipeRefreshLayout Android.
- Quando hai bisogno di adattatori personalizzati per le liste torna alla guida su BaseAdapter Android.
- Per mostrare stati di caricamento nella UI puoi partire dalla guida a ProgressBar Android.
- Per una panoramica completa delle risorse su Android in Java visita l'hub Guide Android Java.