I have a problem: I have a TextView whose content is constantly changing via LiveData. This looks all right when the animation isn't executing, but when the MotionLayout starts executing, my text gets blocked a little bit. And the constraints of my TextView and Button are packed.
activity:
class ErrorActivity : AppCompatActivity() {
private val mViewModel by viewModels<ErrorViewModel>()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
DataBindingUtil.setContentView<ActivityErrorBinding>(this, R.layout.activity_error).apply {
lifecycleOwner = this@ErrorActivity
viewModel = mViewModel
}
}
fun startStopAnim(v: View) {
mViewModel.anim()
}
}
activity layout:
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:binding="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools">
<data>
<variable
name="viewModel"
type="com.test.test.ErrorViewModel" />
</data>
<androidx.constraintlayout.motion.widget.MotionLayout
android:id="@+id/layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layoutDescription="@xml/scene"
binding:anim="@{viewModel.mAnim}">
<TextView
android:id="@+id/tv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{@string/test(viewModel.mCountDown)}"
android:textSize="32sp"
app:layout_constraintEnd_toStartOf="@+id/btn"
app:layout_constraintHorizontal_chainStyle="packed"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:text="@string/test" />
<Button
android:id="@+id/btn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Test"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/tv"
app:layout_constraintTop_toTopOf="parent" />
<Button
android:id="@+id/anim"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="startStopAnim"
android:text="startOrStop"
android:textAllCaps="false"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.motion.widget.MotionLayout>
</layout>
viewModel:
class ErrorViewModel : ViewModel() {
private val _countDown: MutableLiveData<String> = MutableLiveData()
val mCountDown: LiveData<String> = _countDown
private val _anim: MutableLiveData<Boolean> = MutableLiveData()
val mAnim: LiveData<Boolean> = _anim
private var count = 0
private var state = false
init {
viewModelScope.launch(Dispatchers.IO) {
while (true) {
delay(1000)
_countDown.postValue(count++.toString())
}
}
}
fun anim() {
state = !state
_anim.value = state
}
}
@BindingAdapter("anim")
fun anim(layout: MotionLayout, play: Boolean?) {
play?.let {
if (it) {
layout.transitionToEnd()
} else {
layout.transitionToStart()
}
}
}
motionScene:
For simplicity, Scene has only one duration
<?xml version="1.0" encoding="utf-8"?>
<MotionScene xmlns:app="http://schemas.android.com/apk/res-auto">
<Transition
app:constraintSetEnd="@+id/end"
app:constraintSetStart="@+id/start"
app:duration="2000" />
</MotionScene>
gif As you can see in the gif, when there is no click, everything works fine for the numbers, but when I click the button, a 2 second animation starts, during which time my text doesn't display properly. Of course, this is just a demo example. In a real scene, not only the text is not displayed completely, but even the TextView And ImageView are misplaced, and once the animation is executed, it cannot be recovered. Can someone help me...
Actually in a real scene, the parent layout (B) of the problematic TextView (A) would perform a displacement animation. As long as this animation is executed once, the constraint relationship of TextView A will definitely have problems and cannot be restored (onResume can be restored after onPause is currently found)
By design during animation MotionLayout does not honor requestLayout. Because in the majority of applications it is not needed and would have a significant impact on performance.
To enable it in the transition add
<Transition ... motion:layoutDuringTransition="honorRequest" \>