Na versão ConstraintLayout
2.1, vários recursos foram adicionados para ajudar
a gerenciar dispositivos dobráveis, incluindo SharedValues
,
ReactiveGuide
e suporte avançado a animações com o MotionLayout
.
Valores compartilhados
Adicionamos um novo mecanismo para injetar valores de ambiente de execução em ConstraintLayout
.
Esse recurso foi criado para valores de todo o sistema, já que todas as instâncias de
ConstraintLayout
podem acessar o valor.
No contexto de dispositivos dobráveis, podemos usar esse mecanismo para injetar a posição da dobra no momento da execução:
Kotlin
ConstraintLayout.getSharedValues().fireNewValue(R.id.fold, fold)
Java
ConstraintLayout.getSharedValues().fireNewValue(R.id.fold, fold);
Em um auxiliar personalizado, é possível acessar os valores compartilhados adicionando um listener para qualquer mudança:
Kotlin
val sharedValues: SharedValues = ConstraintLayout.getSharedValues() sharedValues.addListener(mAttributeId, this)
Java
SharedValues sharedValues = ConstraintLayout.getSharedValues(); sharedValues.addListener(mAttributeId, this);
Consulte o exemplo de dispositivos dobráveis
para capturar a posição da dobra usando a biblioteca
Jetpack WindowManager e injetar
a posição em 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()
usa um ID que representa o valor como o primeiro parâmetro e
o valor a ser injetado como o segundo parâmetro.
ReactiveGuide
Uma maneira de aproveitar um SharedValue
em um layout sem precisar
programar nenhum código é usar o auxiliar
ReactiveGuide
. Isso posiciona uma diretriz horizontal ou vertical de acordo com o
SharedValue
vinculado.
<androidx.constraintlayout.widget.ReactiveGuide
android:id="@+id/fold"
app:reactiveGuide_valueId="@id/fold"
android:orientation="horizontal" />
Depois disso, você poderá usá-la da mesma forma que faria com uma diretriz normal.
MotionLayout
para dispositivos dobráveis
Adicionamos vários recursos ao MotionLayout
na versão 2.1 que ajuda a transformar
o estado. Isso é particularmente útil para dispositivos dobráveis, já que normalmente
precisamos processar a animação entre os diferentes layouts possíveis.
Há duas abordagens disponíveis para dispositivos dobráveis:
- Durante a execução, atualize o layout atual (
ConstraintSet
) para mostrar ou ocultar a dobra. - Use um
ConstraintSet
separado para cada um dos estados dobráveis que você quer oferecer suporte (closed
,folded
oufully open
).
Como animar um ConstraintSet
A função updateStateAnimate()
em MotionLayout
foi adicionada na versão 2.1:
Kotlin
fun updateStateAnimate(stateId: Int, set: ConstraintSet, duration: Int)
Java
void updateStateAnimate(int stateId, ConstraintSet set, int duration);
Essa função anima automaticamente as mudanças ao atualizar uma determinada
ConstraintSet
, em vez de fazer uma atualização imediata (o que pode ser feito com
updateState(stateId, constraintset)
). Isso permite que você atualize a interface em
tempo real, dependendo de mudanças, como em qual estado dobrável você está.
ReactiveGuide
em um MotionLayout
ReactiveGuide
também oferece suporte a dois atributos úteis quando usado dentro de um
MotionLayout
:
app:reactiveGuide_animateChange="true|false"
app:reactiveGuide_applyToAllConstraintSets="true|false"
O primeiro modifica a ConstraintSet
atual e anima a mudança
automaticamente. O segundo aplicará o novo valor da posição ReactiveGuide
a todos os ConstraintSet
s no MotionLayout
. Uma abordagem típica para
dispositivos dobráveis é usar um ReactiveGuide
que representa a posição da dobra,
configurando os elementos de layout em relação à ReactiveGuide
.
Como usar vários ConstraintSet
s para representar o estado dobrável
Em vez de atualizar o estado atual da MotionLayout
, outra maneira de arquitetar
sua interface para oferecer suporte a dispositivos dobráveis é criando estados separados específicos (incluindo
closed
, folded
e fully open
).
Nesse cenário, você ainda pode usar um ReactiveGuide
para representar a
dobra, mas teria muito mais controle (em comparação com a animação
automatizada ao atualizar a ConstraintSet
atual) sobre como cada estado seria
transferido para outro.
Com essa abordagem, no listener DeviceState
, você simplesmente direcionaria a
MotionLayout
para fazer a transição para estados específicos pelo
método
MotionLayout.transitionToState(stateId)
.