En la ConstraintLayout
2.1, se agregaron varias funciones para ayudar
administrar dispositivos plegables, como SharedValues
,
ReactiveGuide
y la compatibilidad mejorada con las animaciones con MotionLayout
.
Valores compartidos
Agregamos un mecanismo nuevo para insertar valores de entorno de ejecución en ConstraintLayout
:
está diseñado para usarse con valores en todo el sistema, ya que todas las instancias de
ConstraintLayout
pueden acceder al valor.
En el contexto de los dispositivos plegables, podemos usar este mecanismo para inyectar la posición del pliegue en el tiempo de ejecución:
Kotlin
ConstraintLayout.getSharedValues().fireNewValue(R.id.fold, fold)
Java
ConstraintLayout.getSharedValues().fireNewValue(R.id.fold, fold);
En un asistente personalizado, puedes acceder a los valores compartidos agregando un objeto de escucha para cualquier cambio:
Kotlin
val sharedValues: SharedValues = ConstraintLayout.getSharedValues() sharedValues.addListener(mAttributeId, this)
Java
SharedValues sharedValues = ConstraintLayout.getSharedValues(); sharedValues.addListener(mAttributeId, this);
Consulta el ejemplo de FoldableExperiments.
para ver cómo capturamos la posición del pliegue con la
Biblioteca de Jetpack WindowManager e inyectar
la posición en 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()
toma un ID que representa el valor como primer parámetro.
el valor que se insertará como segundo parámetro.
ReactiveGuide
Una forma de aprovechar SharedValue
en un diseño sin tener que hacerlo
escribir código es usar ReactiveGuide
como un asistente de chat. Esto posicionará una guía horizontal o vertical según el
vinculado SharedValue
.
<androidx.constraintlayout.widget.ReactiveGuide
android:id="@+id/fold"
app:reactiveGuide_valueId="@id/fold"
android:orientation="horizontal" />
Podrás usarla como lo harías con una guía normal.
MotionLayout
para dispositivos plegables
Agregamos varias funciones a MotionLayout
en 2.1 que ayudan a
algo particularmente útil para los dispositivos plegables, ya que solemos
tendrás que controlar la animación entre los diferentes diseños posibles.
Hay dos enfoques disponibles para los dispositivos plegables:
- Durante el tiempo de ejecución, actualiza el diseño actual (
ConstraintSet
) para ocultar o mostrar el elemento de la línea de plegado. - Usa un
ConstraintSet
independiente para cada uno de los estados de dispositivo plegable que quieras (closed
,folded
ofully open
).
Cómo animar un ConstraintSet
La función updateStateAnimate()
en MotionLayout
se agregó en la versión 2.1
lanzamiento:
Kotlin
fun updateStateAnimate(stateId: Int, set: ConstraintSet, duration: Int)
Java
void updateStateAnimate(int stateId, ConstraintSet set, int duration);
Esta función animará automáticamente los cambios cuando se actualice un
ConstraintSet
en lugar de realizar una actualización inmediata (lo que puedes hacer con
updateState(stateId, constraintset)
). Esto te permite actualizar la IU en
la mosca, según los cambios, como el estado plegable en el que te encuentres.
ReactiveGuide
dentro de una MotionLayout
ReactiveGuide
también admite dos atributos útiles cuando se usa dentro de un
MotionLayout
app:reactiveGuide_animateChange="true|false"
app:reactiveGuide_applyToAllConstraintSets="true|false"
El primero modificará el ConstraintSet
actual y animará el cambio.
automáticamente. La segunda aplicará el valor nuevo de ReactiveGuide
.
a todos los ConstraintSet
de MotionLayout
. Un enfoque típico para
dispositivos plegables sería usar un ReactiveGuide
que represente la posición del pliegue.
la configuración de tus elementos de diseño en relación con el ReactiveGuide
Cómo usar varios ConstraintSet
para representar el estado plegable
En lugar de actualizar el estado actual de MotionLayout
, otra forma de diseñar la arquitectura
para dispositivos plegables con dispositivos plegables
es crear estados separados específicos (como
closed
, folded
y fully open
).
En este caso, es posible que quieras usar un ReactiveGuide
para representar el
pero tendrías mucho más control (en comparación con la
al actualizar el ConstraintSet
actual) en cómo se vería cada estado
transición a otra.
Con este enfoque, en tu objeto de escucha DeviceState
, simplemente diriges el elemento
MotionLayout
para hacer la transición a estados específicos mediante la
MotionLayout.transitionToState(stateId)
.