In Version 2.1 von ConstraintLayout
wurden mehrere Funktionen zur Verwaltung von faltbaren Geräten hinzugefügt, darunter SharedValues
und ReactiveGuide
. Außerdem wurde die Unterstützung für Animationen mit MotionLayout
verbessert.
Gemeinsame Werte
Wir haben einen neuen Mechanismus zum Einfügen von Laufzeitwerten in ConstraintLayout
hinzugefügt. Er soll für systemweite Werte verwendet werden, da alle Instanzen von ConstraintLayout
auf den Wert zugreifen können.
Im Kontext faltbarer Geräte können wir diesen Mechanismus verwenden, um die Position des Scrollens während der Laufzeit zu übernehmen:
Kotlin
ConstraintLayout.getSharedValues().fireNewValue(R.id.fold, fold)
Java
ConstraintLayout.getSharedValues().fireNewValue(R.id.fold, fold);
In einem benutzerdefinierten Hilfsprogramm können Sie auf die gemeinsamen Werte zugreifen. Dazu fügen Sie für alle Änderungen einen Listener hinzu:
Kotlin
val sharedValues: SharedValues = ConstraintLayout.getSharedValues() sharedValues.addListener(mAttributeId, this)
Java
SharedValues sharedValues = ConstraintLayout.getSharedValues(); sharedValues.addListener(mAttributeId, this);
Das FoldableExperiments-Beispiel zeigt, wie wir die Position des Scrollens mithilfe der Jetpack WindowManager-Bibliothek erfassen und in ConstraintLayout
einfügen.
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); } } } } }
Für fireNewValue()
wird eine ID verwendet, die den Wert als ersten Parameter und den als zweiten Parameter einzufügenden Wert darstellt.
ReactiveGuide
Eine Möglichkeit, die Vorteile von SharedValue
in einem Layout zu nutzen, ohne Code schreiben zu müssen, besteht darin, das Helper-Tool ReactiveGuide
zu verwenden. Dadurch wird eine horizontale oder vertikale Richtlinie gemäß der verknüpften SharedValue
positioniert.
<androidx.constraintlayout.widget.ReactiveGuide
android:id="@+id/fold"
app:reactiveGuide_valueId="@id/fold"
android:orientation="horizontal" />
Sie können es dann wie gewohnt mit einer normalen Richtlinie verwenden.
MotionLayout
für faltbare Smartphones
In Version 2.1 haben wir mehrere Funktionen für MotionLayout
hinzugefügt, die das Morphen des Zustands erleichtern. Das ist besonders für faltbare Smartphones nützlich, da wir normalerweise die Animation zwischen den verschiedenen möglichen Layouts handhaben müssen.
Für faltbare Smartphones gibt es zwei Ansätze:
- Aktualisieren Sie zur Laufzeit das aktuelle Layout (
ConstraintSet
), um das Layout ein- oder auszublenden. - Verwende eine separate
ConstraintSet
für jeden faltbaren Status, den du unterstützen möchtest (closed
,folded
oderfully open
).
ConstraintSet
wird animiert
Die Funktion updateStateAnimate()
in MotionLayout
wurde in Version 2.1 hinzugefügt:
Kotlin
fun updateStateAnimate(stateId: Int, set: ConstraintSet, duration: Int)
Java
void updateStateAnimate(int stateId, ConstraintSet set, int duration);
Mit dieser Funktion werden die Änderungen beim Aktualisieren eines bestimmten ConstraintSet
automatisch animiert, anstatt ein sofortiges Update durchzuführen (was mit updateState(stateId, constraintset)
möglich ist). So können Sie Ihre Benutzeroberfläche im Handumdrehen aktualisieren, je nach Änderungen, z. B. in welchem faltbaren Zustand Sie sich befinden.
ReactiveGuide
in einem MotionLayout
ReactiveGuide
unterstützt außerdem zwei nützliche Attribute, wenn es innerhalb einer MotionLayout
verwendet wird:
app:reactiveGuide_animateChange="true|false"
app:reactiveGuide_applyToAllConstraintSets="true|false"
Mit dem ersten wird der aktuelle ConstraintSet
geändert und die Änderung automatisch animiert. Die zweite wendet den neuen Wert der Position ReactiveGuide
auf alle ConstraintSet
s in MotionLayout
an. Ein typischer Ansatz für faltbare Smartphones wäre, ein ReactiveGuide
-Element zu verwenden, das die Faltposition darstellt. Dabei werden die Layoutelemente relativ zum ReactiveGuide
eingerichtet.
Mehrere ConstraintSet
s zur Darstellung des faltbaren Zustands verwenden
Anstatt den aktuellen MotionLayout
-Status zu aktualisieren, können Sie Ihre UI für die Unterstützung faltbarer Geräte auch erstellen, indem Sie bestimmte separate Status (einschließlich closed
, folded
und fully open
) erstellen.
In diesem Szenario sollten Sie möglicherweise trotzdem ein ReactiveGuide
verwenden, um den „Fold“ darzustellen. Allerdings hätten Sie (im Vergleich zur automatischen Animation beim Aktualisieren des aktuellen ConstraintSet
) viel mehr Kontrolle darüber, wie jeder Zustand in einen anderen übergeht.
Bei diesem Ansatz leiten Sie MotionLayout
in Ihrem DeviceState
-Listener einfach über die Methode MotionLayout.transitionToState(stateId)
an, in bestimmte Zustände zu wechseln.