在 ConstraintLayout
2.1 版本中,我们添加了多项功能来帮助管理可折叠设备,包括 SharedValues
、ReactiveGuide
,以及通过 MotionLayout
增强了对动画的支持。
共享值
我们在 ConstraintLayout
中添加了一种注入运行时值的新机制,这旨在用于系统级值,因为 ConstraintLayout
的所有实例都能够访问该值。
对于可折叠设备,我们可以使用此机制在运行时注入折叠边的位置:
Kotlin
ConstraintLayout.getSharedValues().fireNewValue(R.id.fold, fold)
Java
ConstraintLayout.getSharedValues().fireNewValue(R.id.fold, fold);
在自定义帮助程序中,您可以通过添加监听器来访问共享值:
Kotlin
val sharedValues: SharedValues = ConstraintLayout.getSharedValues() sharedValues.addListener(mAttributeId, this)
Java
SharedValues sharedValues = ConstraintLayout.getSharedValues(); sharedValues.addListener(mAttributeId, this);
您可以查看 FoldableExperiments 示例,了解我们如何使用 Jetpack WindowManager 库捕获折叠边的位置,并将该位置注入 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()
接受一个 ID,该 ID 表示值的第一个参数,而要注入的值作为第二个参数。
ReactiveGuide
若要在不编写任何代码的情况下在布局中利用 SharedValue
,一种方式是使用 ReactiveGuide
辅助程序。这将根据关联的 SharedValue
放置水平或垂直引导线。
<androidx.constraintlayout.widget.ReactiveGuide
android:id="@+id/fold"
app:reactiveGuide_valueId="@id/fold"
android:orientation="horizontal" />
然后,您可以像按照一般准则那样使用它。
MotionLayout
(适用于可折叠设备)
我们在 2.1 版 MotionLayout
中添加了一些有助于变形状态的功能,这对可折叠设备特别有用,因为我们通常需要处理不同可能的布局之间的动画效果。
适用于可折叠设备的方法有两种:
- 在运行时,更新当前布局 (
ConstraintSet
) 以显示或隐藏折叠边。 - 为您要支持的每个可折叠设备状态(
closed
、folded
或fully open
)使用单独的ConstraintSet
。
为 ConstraintSet
添加动画效果
2.1 版本中新增了 MotionLayout
中的 updateStateAnimate()
函数:
Kotlin
fun updateStateAnimate(stateId: Int, set: ConstraintSet, duration: Int)
Java
void updateStateAnimate(int stateId, ConstraintSet set, int duration);
更新给定的 ConstraintSet
时,此函数会自动为更改添加动画效果,而不是立即更新(您可以使用 updateState(stateId, constraintset)
执行此操作)。这样一来,您就可以根据更改(例如您所处的可折叠状态)实时更新界面。
MotionLayout
中的 ReactiveGuide
在 MotionLayout
内使用时,ReactiveGuide
还支持以下两个有用的属性:
app:reactiveGuide_animateChange="true|false"
app:reactiveGuide_applyToAllConstraintSets="true|false"
第一个文件将修改当前的 ConstraintSet
,并自动为更改添加动画效果。第二个请求会将 ReactiveGuide
位置的新值应用于 MotionLayout
中的所有 ConstraintSet
。可折叠设备的典型方法是使用表示折叠位置的 ReactiveGuide
,设置相对于 ReactiveGuide
的布局元素。
使用多个 ConstraintSet
表示可折叠设备状态
如需支持可折叠设备,另一种构建界面的方式是创建特定的单独状态(包括 closed
、folded
和 fully open
),而不是更新当前的 MotionLayout
状态。
在这种情况下,您可能仍然需要使用 ReactiveGuide
来表示折叠,但您可以更好地控制(与更新当前 ConstraintSet
时的自动动画相比)如何转换每种状态。
使用此方法,在 DeviceState
监听器中,您只需通过 MotionLayout.transitionToState(stateId)
方法指示 MotionLayout
转换到特定状态即可。