I have a very simple MotionLayout and I'm trying to change the visibility of one of the constraints programatically and have the view reflect that change. However the change isn't reflected until I transition away from the current state and then come back to it. How do you get the view to update itself based on the new constraint immediately? I've tried updateState(), rebuildScene() and invalidate() but none of them seem to do anything.
Here is the view:
<?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>
Here is the 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>
And here's the code where I'm attempting to update the visibility one of the text views after 2 seconds:
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()
}
}
You can see in the gif below, I wait 2 seconds and nothing happens. It's not until I transition to a new state and then come back to the original one that the visibility is updated.
I found a solution!
The solution provided by Phan Van Linh does not work for me (I am using 2.0.0-beta1 constraint version)
Just call .requestLayout() on view you just changed visibility(or other view properties) So in your example:
motion_layout.getConstraintSet(R.id.base)?.let {
it.setVisibility(R.id.left_to_right_text, View.INVISIBLE)
yourView.requestLayout() // <-- this line
}
Due to documentation for requestLayout method it will go through all view`s hierarchy currently in a layout pass.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With