Android 以编程方式更改约束时,MotionLayout 状态未更新
Android MotionLayout state not updating when changing constraint programatically
我有一个非常简单的 MotionLayout,我正在尝试以编程方式更改其中一个约束的可见性,并让视图反映该更改。但是,直到我从当前状态转换然后返回到当前状态,更改才会反映出来。您如何让视图立即根据新约束更新自身?我试过 updateState()
、rebuildScene()
和 invalidate()
,但其中 none 似乎无能为力。
视图如下:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.motion.widget.MotionLayout
android:id="@+id/motion_layout"
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent" xmlns:app="http://schemas.android.com/apk/res-auto"
app:layout_behavior="@string/appbar_scrolling_view_behavior"
tools:showIn="@layout/activity_main"
app:layoutDescription="@xml/motion_scene"
tools:context=".MainActivity">
<TextView
android:id="@+id/left_to_right_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Left to right"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"/>
<TextView
android:id="@+id/top_to_bottom_text"
android:text="Top to bottom"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"/>
</androidx.constraintlayout.motion.widget.MotionLayout>
这是 MotionScene:
<?xml version="1.0" encoding="utf-8"?>
<MotionScene xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<Transition
app:constraintSetStart="@id/base"
app:constraintSetEnd="@id/bottom">
<OnClick
app:targetId="@id/top_to_bottom_text">
</OnClick>
</Transition>
<Transition
app:constraintSetStart="@id/base"
app:constraintSetEnd="@id/right">
<OnSwipe
app:dragDirection="dragRight"
app:touchAnchorId="@id/left_to_right_text"
app:touchAnchorSide="right">
</OnSwipe>
</Transition>
<ConstraintSet android:id="@+id/base">
<Constraint
android:id="@id/left_to_right_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent"/>
<Constraint
android:id="@id/top_to_bottom_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent"/>
</ConstraintSet>
<ConstraintSet android:id="@+id/bottom">
<Constraint
android:id="@id/left_to_right_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent"/>
<Constraint
android:id="@id/top_to_bottom_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
/>
</ConstraintSet>
<ConstraintSet android:id="@+id/right">
<Constraint
android:id="@id/left_to_right_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"/>
<Constraint
android:id="@id/top_to_bottom_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent"/>
</ConstraintSet>
</MotionScene>
下面是我尝试在 2 秒后更新其中一个文本视图的可见性的代码:
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
setSupportActionBar(toolbar)
Completable.timer(2, TimeUnit.SECONDS)
.observeOn(AndroidSchedulers.mainThread())
.subscribe {
motion_layout.getConstraintSet(R.id.base)?.let {
it.setVisibility(R.id.left_to_right_text, View.INVISIBLE)
}
motion_layout.updateState()
// These don't work either
// motion_layout.rebuildScene()
// motion_layout.invalidate()
}
}
你可以在下面的 gif 中看到,我等了 2 秒但没有任何反应。直到我转换到一个新状态然后回到原始状态,可见性才更新。
尝试:
更新状态(R.id.base,约束集)
我找到了解决办法!
Phan Van Linh提供的解决方案对我不起作用(我使用的是2.0.0-beta1约束版本)
只需在刚刚更改可见性(或其他视图属性)的视图上调用 .requestLayout()
所以在你的例子中:
motion_layout.getConstraintSet(R.id.base)?.let {
it.setVisibility(R.id.left_to_right_text, View.INVISIBLE)
yourView.requestLayout() // <-- this line
}
由于 requestLayout 方法的文档,它将遍历当前在布局过程中的所有视图的层次结构。
我有一个非常简单的 MotionLayout,我正在尝试以编程方式更改其中一个约束的可见性,并让视图反映该更改。但是,直到我从当前状态转换然后返回到当前状态,更改才会反映出来。您如何让视图立即根据新约束更新自身?我试过 updateState()
、rebuildScene()
和 invalidate()
,但其中 none 似乎无能为力。
视图如下:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.motion.widget.MotionLayout
android:id="@+id/motion_layout"
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent" xmlns:app="http://schemas.android.com/apk/res-auto"
app:layout_behavior="@string/appbar_scrolling_view_behavior"
tools:showIn="@layout/activity_main"
app:layoutDescription="@xml/motion_scene"
tools:context=".MainActivity">
<TextView
android:id="@+id/left_to_right_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Left to right"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"/>
<TextView
android:id="@+id/top_to_bottom_text"
android:text="Top to bottom"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"/>
</androidx.constraintlayout.motion.widget.MotionLayout>
这是 MotionScene:
<?xml version="1.0" encoding="utf-8"?>
<MotionScene xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<Transition
app:constraintSetStart="@id/base"
app:constraintSetEnd="@id/bottom">
<OnClick
app:targetId="@id/top_to_bottom_text">
</OnClick>
</Transition>
<Transition
app:constraintSetStart="@id/base"
app:constraintSetEnd="@id/right">
<OnSwipe
app:dragDirection="dragRight"
app:touchAnchorId="@id/left_to_right_text"
app:touchAnchorSide="right">
</OnSwipe>
</Transition>
<ConstraintSet android:id="@+id/base">
<Constraint
android:id="@id/left_to_right_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent"/>
<Constraint
android:id="@id/top_to_bottom_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent"/>
</ConstraintSet>
<ConstraintSet android:id="@+id/bottom">
<Constraint
android:id="@id/left_to_right_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent"/>
<Constraint
android:id="@id/top_to_bottom_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
/>
</ConstraintSet>
<ConstraintSet android:id="@+id/right">
<Constraint
android:id="@id/left_to_right_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"/>
<Constraint
android:id="@id/top_to_bottom_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent"/>
</ConstraintSet>
</MotionScene>
下面是我尝试在 2 秒后更新其中一个文本视图的可见性的代码:
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
setSupportActionBar(toolbar)
Completable.timer(2, TimeUnit.SECONDS)
.observeOn(AndroidSchedulers.mainThread())
.subscribe {
motion_layout.getConstraintSet(R.id.base)?.let {
it.setVisibility(R.id.left_to_right_text, View.INVISIBLE)
}
motion_layout.updateState()
// These don't work either
// motion_layout.rebuildScene()
// motion_layout.invalidate()
}
}
你可以在下面的 gif 中看到,我等了 2 秒但没有任何反应。直到我转换到一个新状态然后回到原始状态,可见性才更新。
尝试: 更新状态(R.id.base,约束集)
我找到了解决办法!
Phan Van Linh提供的解决方案对我不起作用(我使用的是2.0.0-beta1约束版本)
只需在刚刚更改可见性(或其他视图属性)的视图上调用 .requestLayout() 所以在你的例子中:
motion_layout.getConstraintSet(R.id.base)?.let {
it.setVisibility(R.id.left_to_right_text, View.INVISIBLE)
yourView.requestLayout() // <-- this line
}
由于 requestLayout 方法的文档,它将遍历当前在布局过程中的所有视图的层次结构。