When CoordinatorLayout is used inside of MotionLayout and while screen scrolling some view requests layout (via requestLayout()
function), the rest of the scrolling is broken.
The layout structure is:
<MotionLayout>
<View/> <!-- Animated with motion scene -->
<CoordinatorLayout>
<AppBarLayout>
<ImageView/> <!-- Requests layout -->
</AppBarLayout>
<RecyclerView/>
</CoordinatorLayout>
<MotionLayout>
The MotionScene:
<MotionScene xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<Transition
app:constraintSetEnd="@id/end"
app:constraintSetStart="@id/start" />
<ConstraintSet android:id="@+id/start">
<Constraint android:id="@id/background">
<PropertySet android:alpha="0" />
</Constraint>
</ConstraintSet>
<ConstraintSet android:id="@+id/end">
<Constraint android:id="@id/background">
<PropertySet android:alpha="1" />
</Constraint>
</ConstraintSet>
</MotionScene>
The animation progress is calculated like this:
appBarLayout.addOnOffsetChangedListener(OnOffsetChangedListener { _, verticalOffset ->
motionLayout.progress = -verticalOffset / appBarLayout.totalScrollRange.toFloat()
})
The key points are next:
requestLayout()
- in my example it happens on ImageView click
After that, any following scrolling will be broken and the layout looks invalid.To identify the root cause I've tried to remove the line with MotionLayout.setProgress()
with the rest of the code remains unchanged. And after that scrolling has worked as expected. After this I decided to put back MotionLayout.setProgress()
and this time I've removed View.requestLayout()
. And this time scrolling works as expected too. But when I'm trying to put back both MotionLayout.setProgress()
and View.requestLayout()
the scrolling broke.
Also I've submitted a bug to the Google issue tracker: https://issuetracker.google.com/u/1/issues/178976381
By default MotionLayout ignores requestLayout during transitions. This is done for performance. To enable in your tag add
layoutDuringTransition="honorRequest"