android / views-widgets-samples

Multiple samples showing the best practices in views-widgets on Android.
Apache License 2.0
5.03k stars 3.01k forks source link

RecyclerView inside MotionLayout doesn't work with OnSwipe dragDown #235

Closed giangpham96 closed 1 year ago

giangpham96 commented 2 years ago

The problem:

I want to have an initial state where the header is 140dp above the recycler view. When the user scrolls up, the header shrinks to 65dp When the user scrolls down, the header expands to 170dp

The approach:

I have my layout as below

<androidx.constraintlayout.motion.widget.MotionLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/motion"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    app:layoutDescription="@xml/sample_collapsing_animation_scene">

       // something on top of the guideline

    <androidx.constraintlayout.widget.Guideline
        android:id="@+id/guideline_toolbar"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:orientation="horizontal"
        app:layout_constraintGuide_begin="140dp" />

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/scrollable_content"
        android:layout_width="0dp"
        android:layout_height="0dp"
        app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintTop_toBottomOf="@id/guideline_toolbar"
        tools:listitem="@layout/dummy_list_item"/>

</androidx.constraintlayout.motion.widget.MotionLayout>

and here is my motion scene

<MotionScene xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:motion="http://schemas.android.com/apk/res-auto">

    <Transition
        motion:constraintSetEnd="@+id/end2"
        motion:constraintSetStart="@id/start"
        motion:motionInterpolator="easeInOut">
        <OnSwipe
            motion:dragDirection="dragDown"
            motion:dragScale="1"
            motion:onTouchUp="stop"
            motion:moveWhenScrollAtTop="true"
            motion:touchAnchorId="@id/scrollable_content"/>
    </Transition>
    <Transition
        motion:constraintSetEnd="@+id/end"
        motion:constraintSetStart="@id/start"
        motion:motionInterpolator="easeInOut">
        <OnSwipe
            motion:dragDirection="dragUp"
            motion:dragScale="1"
            motion:moveWhenScrollAtTop="true"
            motion:onTouchUp="stop"
            motion:touchAnchorId="@id/scrollable_content" />
    </Transition>

    <ConstraintSet android:id="@+id/start">
        // some constraints
    </ConstraintSet>

    <ConstraintSet android:id="@+id/end2">

        <Constraint
            android:id="@+id/guideline_toolbar"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            motion:layout_constraintGuide_begin="170dp" />

                // some other constraints

    </ConstraintSet>

    <ConstraintSet android:id="@+id/end">

                // some other constraints
        <Constraint
            android:id="@+id/guideline_toolbar"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            motion:layout_constraintGuide_begin="65dp" />

    </ConstraintSet>
</MotionScene>

The unexpected behavior:

When the user scrolls down recycler view, nothing happens When the user scrolls up, the header expands when it should collapse. If I remove the first transition, the header collapse when the user scrolls up as expected. If I replace the recycler view with a regular View, the code works as expected.

I guess the reason may be due to the recyclerview is scrollable?