Nella versione 2.1 di ConstraintLayout
sono state aggiunte diverse funzionalità per agevolare la gestione dei dispositivi pieghevoli, tra cui SharedValues
, ReactiveGuide
e il supporto migliorato dell'animazione con MotionLayout
.
Valori condivisi
Abbiamo aggiunto un nuovo meccanismo per inserire i valori di runtime in ConstraintLayout
, da utilizzare per i valori a livello di sistema, poiché tutte le istanze di ConstraintLayout
sono in grado di accedere al valore.
Nel contesto dei dispositivi pieghevoli, possiamo utilizzare questo meccanismo per inserire la posizione del fold in fase di runtime:
Kotlin
ConstraintLayout.getSharedValues().fireNewValue(R.id.fold, fold)
Java
ConstraintLayout.getSharedValues().fireNewValue(R.id.fold, fold);
In un helper personalizzato, puoi accedere ai valori condivisi aggiungendo un listener per qualsiasi modifica:
Kotlin
val sharedValues: SharedValues = ConstraintLayout.getSharedValues() sharedValues.addListener(mAttributeId, this)
Java
SharedValues sharedValues = ConstraintLayout.getSharedValues(); sharedValues.addListener(mAttributeId, this);
Puoi consultare l'esempio di Foldable Experiments per vedere come acquisire la posizione del fold utilizzando la libreria Jetpack WindowManager e iniettare la posizione in ConstraintLayout
.
Kotlin
inner class StateContainer : Consumer<WindowLayoutInfo> { override fun accept(newLayoutInfo: WindowLayoutInfo) { // Add views that represent display features for (displayFeature in newLayoutInfo.displayFeatures) { val foldFeature = displayFeature as? FoldingFeature if (foldFeature != null) { if (foldFeature.isSeparating && foldFeature.orientation == FoldingFeature.Orientation.HORIZONTAL ) { // The foldable device is in tabletop mode val fold = foldPosition(motionLayout, foldFeature) ConstraintLayout.getSharedValues().fireNewValue(R.id.fold, fold) } else { ConstraintLayout.getSharedValues().fireNewValue(R.id.fold, 0); } } } } }
Java
class StateContainer implements Consumer<WindowLayoutInfo> { @Override public void accept(WindowLayoutInfo newLayoutInfo) { // Add views that represent display features for (DisplayFeature displayFeature : newLayoutInfo.getDisplayFeatures()) { if (displayFeature instanceof FoldingFeature) { FoldingFeature foldFeature = (FoldingFeature)displayFeature; if (foldFeature.isSeparating() && foldFeature.getOrientation() == FoldingFeature.Orientation.HORIZONTAL ) { // The foldable device is in tabletop mode int fold = foldPosition(motionLayout, foldFeature); ConstraintLayout.getSharedValues().fireNewValue(R.id.fold, fold); } else { ConstraintLayout.getSharedValues().fireNewValue(R.id.fold, 0); } } } } }
fireNewValue()
prende un ID che rappresenta il valore come primo parametro e il valore da inserire come secondo parametro.
ReactiveGuide
Un modo per sfruttare SharedValue
in un layout senza dover scrivere alcun codice è utilizzare l'helper ReactiveGuide
. In questo modo, verrà posizionata una linea guida orizzontale o verticale in base al
SharedValue
collegato.
<androidx.constraintlayout.widget.ReactiveGuide
android:id="@+id/fold"
app:reactiveGuide_valueId="@id/fold"
android:orientation="horizontal" />
Può quindi essere utilizzato come faresti con una normale linea guida.
MotionLayout
per i pieghevoli
Abbiamo aggiunto diverse funzionalità in MotionLayout
nella versione 2.1 che consentono il morphing dello stato, una funzionalità particolarmente utile per i pieghevoli, dato che in genere dobbiamo gestire l'animazione tra i diversi layout possibili.
Sono disponibili due approcci per i pieghevoli:
- In fase di runtime, aggiorna il layout corrente (
ConstraintSet
) per mostrare o nascondere il pulsante. - Utilizza un elemento
ConstraintSet
separato per ogni stato pieghevole che vuoi supportare (closed
,folded
ofully open
).
Animazione di un elemento ConstraintSet
La funzione updateStateAnimate()
in MotionLayout
è stata aggiunta nella release 2.1:
Kotlin
fun updateStateAnimate(stateId: Int, set: ConstraintSet, duration: Int)
Java
void updateStateAnimate(int stateId, ConstraintSet set, int duration);
Questa funzione anima automaticamente le modifiche durante l'aggiornamento di un determinato
ConstraintSet
anziché eseguire un aggiornamento immediato (puoi farlo con
updateState(stateId, constraintset)
). In questo modo puoi aggiornare la tua UI
in tempo reale a seconda delle modifiche, ad esempio lo stato pieghevole in cui ti trovi.
ReactiveGuide
in un MotionLayout
ReactiveGuide
supporta anche due attributi utili quando utilizzato all'interno di un
MotionLayout
:
app:reactiveGuide_animateChange="true|false"
app:reactiveGuide_applyToAllConstraintSets="true|false"
Il primo modifica l'attuale ConstraintSet
e anima automaticamente la modifica. Il secondo applicherà il nuovo valore della posizione ReactiveGuide
a tutte le ConstraintSet
in MotionLayout
. Un approccio tipico per gli elementi pieghevoli consiste nell'utilizzare un ReactiveGuide
che rappresenta la posizione di piegatura, configurando gli elementi del layout in base a ReactiveGuide
.
Utilizzo di più ConstraintSet
per rappresentare lo stato pieghevole
Anziché aggiornare l'attuale stato MotionLayout
, un altro modo per progettare la tua UI per il supporto dei pieghevoli consiste nel creare stati separati specifici (inclusi closed
, folded
e fully open
).
In questo scenario, potresti comunque voler utilizzare un ReactiveGuide
per rappresentare il
fold, ma avrai un controllo molto maggiore (rispetto all'animazione automatica
quando si aggiorna l'attuale ConstraintSet
) sul modo in cui ogni stato passerebbe a un altro.
Con questo approccio, per chi ascolta DeviceState
puoi semplicemente indicare all'MotionLayout
di passare a stati specifici usando il metodo MotionLayout.transitionToState(stateId)
.