No ConstraintLayout
versão 2.1, vários recursos foram adicionados para ajudar
gerenciar dispositivos dobráveis, incluindo SharedValues
,
ReactiveGuide
e suporte aprimorado a animação com MotionLayout
.
Valores compartilhados
Adicionamos um novo mecanismo para injetar valores de ambiente de execução em ConstraintLayout
:
Ela se destina a valores em 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 assistente personalizado, você pode acessar os valores compartilhados adicionando um listener para alguma alteração:
Kotlin
val sharedValues: SharedValues = ConstraintLayout.getSharedValues() sharedValues.addListener(mAttributeId, this)
Java
SharedValues sharedValues = ConstraintLayout.getSharedValues(); sharedValues.addListener(mAttributeId, this);
Consulte o exemplo do FoldableExperiments.
para ver como capturamos a posição da dobra usando o
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 usar uma SharedValue
em um layout, sem precisar
escrever códigos, é usar o ReactiveGuide
ajudante. Isso posicionará uma linha guia horizontal ou vertical de acordo com o
vinculado a SharedValue
.
<androidx.constraintlayout.widget.ReactiveGuide
android:id="@+id/fold"
app:reactiveGuide_valueId="@id/fold"
android:orientation="horizontal" />
Em seguida, ele pode ser usado como uma diretriz normal.
MotionLayout
para dispositivos dobráveis
Adicionamos vários recursos à versão 2.1 do MotionLayout
que ajudam na transformação
algo útil para dispositivos dobráveis, já que
precisa lidar com 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 o dobra. - Use uma
ConstraintSet
separada para cada um dos estados dobráveis que você quer compatíveis (closed
,folded
oufully open
).
Como animar um ConstraintSet
A função updateStateAnimate()
em MotionLayout
foi adicionada à versão 2.1
lançamento:
Kotlin
fun updateStateAnimate(stateId: Int, set: ConstraintSet, duration: Int)
Java
void updateStateAnimate(int stateId, ConstraintSet set, int duration);
Esta função animará automaticamente as mudanças ao atualizar um determinado
ConstraintSet
em vez de fazer uma atualização imediata, que você pode fazer com
updateState(stateId, constraintset)
). Isso permite atualizar a interface
com facilidade, dependendo das 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 vai modificar o ConstraintSet
atual e animar a mudança.
automaticamente. O segundo vai aplicar o novo valor de ReactiveGuide
.
para todos os ConstraintSet
s no MotionLayout
. Uma abordagem típica
dobráveis seriam usar um ReactiveGuide
para representar 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
que sua interface ofereça suporte a dispositivos dobráveis é criar estados separados específicos, incluindo
closed
, folded
e fully open
).
Nesse cenário, ainda convém usar um ReactiveGuide
para representar o
mas você teria muito mais controle (em comparação com as campanhas
ao atualizar a ConstraintSet
atual) sobre como cada estado
passar para outro.
Com essa abordagem, no listener DeviceState
, você simplesmente direcionaria o
MotionLayout
para fazer a transição para estados específicos usando o
MotionLayout.transitionToState(stateId)
.