Designs für faltbare Smartphones und Tablets entwickeln

In der ConstraintLayout Version 2.1 wurden mehrere neue Funktionen faltbare Geräte verwalten, darunter SharedValues, ReactiveGuide und erweiterte Unterstützung für Animationen mit MotionLayout.

Gemeinsame Werte

Wir haben einen neuen Mechanismus hinzugefügt, um Laufzeitwerte in ConstraintLayout einzufügen: Dieser ist für systemweite Werte vorgesehen, da alle Instanzen ConstraintLayout können auf den Wert zugreifen.

Bei faltbaren Geräten können wir mit diesem Mechanismus den Position des Fold zur Laufzeit:

Kotlin

ConstraintLayout.getSharedValues().fireNewValue(R.id.fold, fold)

Java

ConstraintLayout.getSharedValues().fireNewValue(R.id.fold, fold);

In einer benutzerdefinierten Hilfsfunktion können Sie auf die freigegebenen Werte zugreifen, indem Sie einen Listener für Änderungen:

Kotlin

val sharedValues: SharedValues = ConstraintLayout.getSharedValues()
sharedValues.addListener(mAttributeId, this)

Java

SharedValues sharedValues = ConstraintLayout.getSharedValues();
sharedValues.addListener(mAttributeId, this);

Sehen Sie sich das FoldableExperiments-Beispiel an. um zu sehen, wie wir die Position der Falte mithilfe des Jetpack WindowManager-Bibliothek und Injection die Position in ConstraintLayout ein.

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() verwendet eine ID, die den Wert als ersten Parameter darstellt, und den als zweiten Parameter einzufügenden Wert.

ReactiveGuide

Eine Möglichkeit, SharedValue in einem Layout zu nutzen, ohne Code zu schreiben, besteht darin, ReactiveGuide Hilfsprogramm. Dadurch wird eine horizontale oder vertikale Führungslinie entsprechend der verknüpfte SharedValue.

    <androidx.constraintlayout.widget.ReactiveGuide
        android:id="@+id/fold"
        app:reactiveGuide_valueId="@id/fold"
        android:orientation="horizontal" />

Sie kann dann wie eine normale Richtlinie verwendet werden.

MotionLayout für faltbare Geräte

Wir haben in Version 2.1 mehrere Funktionen zu MotionLayout hinzugefügt, die das Morphen etwas besonders nützlich für faltbare Geräte. zwischen den verschiedenen möglichen Layouts animieren müssen.

Es gibt zwei Ansätze für faltbare Geräte:

  • Aktualisieren Sie während der Laufzeit das aktuelle Layout (ConstraintSet), um die gefaltet werden.
  • Verwende für jeden faltbaren Status, den du ändern möchtest, eine separate ConstraintSet (closed, folded oder fully open).

ConstraintSet animieren

Die Funktion updateStateAnimate() in MotionLayout wurde in 2.1 hinzugefügt. Release:

Kotlin

fun updateStateAnimate(stateId: Int, set: ConstraintSet, duration: Int)

Java

void updateStateAnimate(int stateId, ConstraintSet set, int duration);

Mit dieser Funktion werden die Änderungen automatisch animiert, wenn ein ConstraintSet statt einer sofortigen Aktualisierung (was Sie mit updateState(stateId, constraintset)). So können Sie Ihre UI auf je nachdem, in welchem Zustand du dich gerade befindest, z. B. in welchem faltbaren Zustand.

ReactiveGuide in MotionLayout

ReactiveGuide unterstützt auch zwei nützliche Attribute, wenn sie innerhalb eines MotionLayout:

  • app:reactiveGuide_animateChange="true|false"

  • app:reactiveGuide_applyToAllConstraintSets="true|false"

Mit der ersten Option wird der aktuelle ConstraintSet geändert und die Änderung animiert. automatisch. Bei der zweiten wird der neue Wert von ReactiveGuide angewendet. Position für alle ConstraintSets in MotionLayout. Ein typischer Ansatz für ReactiveGuide, die für die faltbare Position steht, zum Einrichten Ihrer Layoutelemente relativ zum ReactiveGuide.

Mehrere ConstraintSets zur Darstellung des faltbaren Status verwenden

Statt den aktuellen MotionLayout-Status zu aktualisieren, können Sie Ihre Benutzeroberfläche zur Unterstützung faltbarer Geräte ist die Erstellung separater Status (einschließlich closed, folded und fully open).

Auch in diesem Szenario kann es sinnvoll sein, ReactiveGuide für die Darstellung des gefaltet, hätten Sie aber viel mehr Kontrolle (im Vergleich zu den automatisierten beim Aktualisieren der aktuellen ConstraintSet) zeigt, wie die einzelnen Status in eine andere übergehen.

Bei diesem Ansatz weisen Sie im DeviceState-Listener einfach den MotionLayout, um über die MotionLayout.transitionToState(stateId) .