W wersji ConstraintLayout
2.1 dodaliśmy kilka funkcji, które ułatwiają zarządzanie urządzeniami składanymi, w tym SharedValues
i ReactiveGuide
oraz ulepszoną obsługę animacji w wersji MotionLayout
.
Wspólne wartości
Dodaliśmy nowy mechanizm wstrzykiwania wartości środowiska wykonawczego w komponencie ConstraintLayout
. Jest on przeznaczony dla wartości w całym systemie, ponieważ dostęp do wartości mają wszystkie instancje funkcji ConstraintLayout
.
W przypadku urządzeń składanych możemy wykorzystać ten mechanizm, aby określić położenie składane w czasie działania:
Kotlin
ConstraintLayout.getSharedValues().fireNewValue(R.id.fold, fold)
Java
ConstraintLayout.getSharedValues().fireNewValue(R.id.fold, fold);
W niestandardowym interfejsie pomocniczym możesz uzyskać dostęp do wspólnych wartości, dodając odbiornik zmian:
Kotlin
val sharedValues: SharedValues = ConstraintLayout.getSharedValues() sharedValues.addListener(mAttributeId, this)
Java
SharedValues sharedValues = ConstraintLayout.getSharedValues(); sharedValues.addListener(mAttributeId, this);
Zapoznaj się z przykładem aplikacji Foldable Experiments, aby zobaczyć, jak za pomocą biblioteki Jetpack WindowManager rejestrujemy położenie strony widocznej na ekranie i wprowadzamy ją w elemencie 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()
pobiera identyfikator reprezentujący wartość jako pierwszy parametr i wartość do wstrzykiwania jako drugi parametr.
ReactiveGuide
Jednym ze sposobów wykorzystania elementu SharedValue
w układzie bez konieczności pisania kodu jest skorzystanie z elementu pomocniczego ReactiveGuide
. Spowoduje to ustawienie pozycji poziomej lub pionowej wskazówki zgodnie z połączonym SharedValue
.
<androidx.constraintlayout.widget.ReactiveGuide
android:id="@+id/fold"
app:reactiveGuide_valueId="@id/fold"
android:orientation="horizontal" />
Możesz go używać tak samo jak ze standardowymi wytycznymi.
MotionLayout
– urządzenia składane
W usłudze MotionLayout
w wersji 2.1 dodaliśmy kilka funkcji, które ułatwiają przekształcanie urządzeń, co przydaje się zwłaszcza w przypadku urządzeń składanych, ponieważ zazwyczaj musimy obsługiwać animowanie między różnymi możliwymi układami.
W przypadku urządzeń składanych dostępne są 2 sposoby:
- W czasie działania zaktualizuj bieżący układ (
ConstraintSet
), aby wyświetlić lub ukryć część strony widoczną na ekranie. - Użyj osobnego elementu
ConstraintSet
w przypadku każdego stanu składanego, który chcesz obsługiwać (closed
,folded
lubfully open
).
Optymalizuję: ConstraintSet
Funkcja updateStateAnimate()
w MotionLayout
została dodana w wersji 2.1:
Kotlin
fun updateStateAnimate(stateId: Int, set: ConstraintSet, duration: Int)
Java
void updateStateAnimate(int stateId, ConstraintSet set, int duration);
Ta funkcja automatycznie animuje zmiany podczas aktualizowania danego elementu ConstraintSet
, zamiast przeprowadzać natychmiastową aktualizację (możesz to zrobić za pomocą updateState(stateId, constraintset)
). Dzięki temu możesz aktualizować interfejs na bieżąco w zależności od zmian, takich jak Twój stan składany.
ReactiveGuide
w: MotionLayout
Atrybut ReactiveGuide
[MotionLayout
] obsługuje też 2 przydatne atrybuty:
app:reactiveGuide_animateChange="true|false"
app:reactiveGuide_applyToAllConstraintSets="true|false"
Pierwszy z nich zmodyfikuje bieżące ConstraintSet
i automatycznie animuje zmianę. Drugie rozwiązanie zastosuje nową wartość pozycji ReactiveGuide
do wszystkich elementów ConstraintSet
w: MotionLayout
. W przypadku urządzeń składanych typowym podejściem jest użycie obiektu ReactiveGuide
reprezentującego pozycję strony widocznej po przewinięciu i ustawienie elementów układu względem elementu ReactiveGuide
.
Używanie wielu elementów ConstraintSet
do reprezentowania stanu składanego
Zamiast aktualizować bieżący stan MotionLayout
, innym sposobem zaprojektowania interfejsu pod kątem obsługi urządzeń składanych jest utworzenie określonych osobnych stanów (w tym closed
, folded
i fully open
).
W tej sytuacji warto użyć elementu ReactiveGuide
do reprezentowania części strony widocznej na ekranie, ale będziesz mieć znacznie większą kontrolę (w porównaniu z automatyczną animacją podczas aktualizacji bieżącej ConstraintSet
) nad sposobem przejścia poszczególnych stanów do innego.
Przy takim podejściu w detektorze DeviceState
będziesz po prostu kierować element MotionLayout
do określonych stanów za pomocą metody MotionLayout.transitionToState(stateId)
.