Dans la version 2.1 de ConstraintLayout
, plusieurs fonctionnalités ont été ajoutées pour faciliter la gestion des appareils pliables, y compris SharedValues
et ReactiveGuide
, ainsi qu'une meilleure compatibilité avec les animations avec MotionLayout
.
Valeurs partagées
Nous avons ajouté un nouveau mécanisme pour injecter des valeurs d'exécution dans ConstraintLayout
. Il est destiné à être utilisé pour les valeurs à l'échelle du système, car toutes les instances de ConstraintLayout
peuvent accéder à la valeur.
Dans le contexte des appareils pliables, nous pouvons utiliser ce mécanisme pour injecter la position du pli au moment de l'exécution:
Kotlin
ConstraintLayout.getSharedValues().fireNewValue(R.id.fold, fold)
Java
ConstraintLayout.getSharedValues().fireNewValue(R.id.fold, fold);
Dans un assistant personnalisé, vous pouvez accéder aux valeurs partagées en ajoutant un écouteur pour toutes les modifications:
Kotlin
val sharedValues: SharedValues = ConstraintLayout.getSharedValues() sharedValues.addListener(mAttributeId, this)
Java
SharedValues sharedValues = ConstraintLayout.getSharedValues(); sharedValues.addListener(mAttributeId, this);
Consultez l'exemple PoldableExperiments pour voir comment capturer la position du pli à l'aide de la bibliothèque Jetpack WindowManager et injecter la position dans 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()
utilise un ID représentant la valeur comme premier paramètre et la valeur à injecter comme deuxième paramètre.
ReactiveGuide
Pour tirer parti d'un SharedValue
dans une mise en page, sans avoir à écrire de code, vous pouvez utiliser l'outil d'aide ReactiveGuide
. Cela permet de positionner une ligne horizontale ou verticale en fonction de l'élément SharedValue
associé.
<androidx.constraintlayout.widget.ReactiveGuide
android:id="@+id/fold"
app:reactiveGuide_valueId="@id/fold"
android:orientation="horizontal" />
Vous pouvez ensuite l'utiliser comme vous le feriez normalement.
MotionLayout
pour les appareils pliables
Nous avons ajouté plusieurs fonctionnalités dans MotionLayout
dans la version 2.1 qui permettent de modifier l'état, ce qui est particulièrement utile pour les pliables, car nous devons généralement gérer l'animation entre les différentes mises en page possibles.
Deux approches sont disponibles pour les appareils pliables:
- Au moment de l'exécution, mettez à jour votre mise en page actuelle (
ConstraintSet
) pour afficher ou masquer le pli. - Utilisez un
ConstraintSet
distinct pour chacun des états d'appareils pliables que vous souhaitez prendre en charge (closed
,folded
oufully open
).
Animer un ConstraintSet
La fonction updateStateAnimate()
dans MotionLayout
a été ajoutée dans la version 2.1:
Kotlin
fun updateStateAnimate(stateId: Int, set: ConstraintSet, duration: Int)
Java
void updateStateAnimate(int stateId, ConstraintSet set, int duration);
Cette fonction animera automatiquement les modifications lors de la mise à jour d'un ConstraintSet
donné au lieu d'effectuer une mise à jour immédiate (ce que vous pouvez faire avec updateState(stateId, constraintset)
). Cela vous permet de mettre à jour votre UI à la volée, en fonction des modifications, comme l'état du pliable dans lequel vous vous trouvez.
ReactiveGuide
dans un élément MotionLayout
ReactiveGuide
accepte également deux attributs utiles lorsqu'il est utilisé dans un MotionLayout
:
app:reactiveGuide_animateChange="true|false"
app:reactiveGuide_applyToAllConstraintSets="true|false"
Le premier modifie le ConstraintSet
actuel et anime ce changement automatiquement. Le second appliquera la nouvelle valeur de la position ReactiveGuide
à tous les ConstraintSet
de MotionLayout
. Une approche typique pour les appareils pliables consiste à utiliser un ReactiveGuide
représentant la position de pliage, en configurant vos éléments de mise en page par rapport à la ReactiveGuide
.
Utiliser plusieurs ConstraintSet
pour représenter l'état d'un appareil pliable
Au lieu de mettre à jour l'état MotionLayout
actuel, une autre façon de concevoir votre UI pour qu'elle soit compatible avec les pliables consiste à créer des états distincts spécifiques (y compris closed
, folded
et fully open
).
Dans ce scénario, vous pouvez toujours utiliser un ReactiveGuide
pour représenter le pli, mais vous auriez beaucoup plus de contrôle (par rapport à l'animation automatisée lors de la mise à jour du ConstraintSet
actuel) sur la façon dont chaque état passerait à un autre.
Avec cette approche, dans votre écouteur DeviceState
, il vous suffit de demander à MotionLayout
de passer à des états spécifiques via la méthode MotionLayout.transitionToState(stateId)
.