Search code examples
androidandroid-animationbottom-sheetandroid-motionlayoutandroid-motionscene

OnSwipe dragUp doesn't work on View with child in MotionLayout


I want to use MotionLayout to implement the Bottom Sheet in my activity.

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/end"
        motion:constraintSetStart="@id/start"
        motion:duration="2000">

        <OnSwipe
            motion:dragDirection="dragUp"
            motion:touchAnchorId="@id/bottomSheet"
            motion:touchRegionId="@id/bottomSheet" />

    </Transition>

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

        <Constraint
            android:id="@+id/bottomSheet"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            motion:layout_constraintBottom_toBottomOf="parent"/>

    </ConstraintSet>

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

        <Constraint
            android:id="@+id/bottomSheet"
            android:layout_width="match_parent"
            android:layout_height="0dp"
            motion:layout_constraintTop_toTopOf="parent"
            motion:layout_constraintBottom_toBottomOf="parent"/>
    
    </ConstraintSet>

</MotionScene>

Now, if I implement my MotionLayout like the following code, I can't dragUp in button area:

<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/ml"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@android:color/darker_gray"
    app:layoutDescription="@xml/activity_main_scene"
    tools:context=".MainActivity">

    <com.google.android.material.card.MaterialCardView
        android:id="@+id/bottomSheet"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        app:cardBackgroundColor="@android:color/black">

        <FrameLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:background="@android:color/holo_red_dark"
            android:padding="40dp">

            <Button
                android:id="@+id/btn"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_gravity="center"
                android:text="A button" />

        </FrameLayout>

    </com.google.android.material.card.MaterialCardView>

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

I can wrap the MaterialCardView with a NestedScrollView then because the NestedScrollView will properly handle onInterceptTouchEvent, it will work:

<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/ml"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@android:color/darker_gray"
    app:layoutDescription="@xml/activity_main_scene"
    tools:context=".MainActivity">

    <androidx.core.widget.NestedScrollView
        android:id="@+id/bottomSheet"
        android:background="@android:color/holo_blue_dark"
        android:layout_width="match_parent"
        android:layout_height="wrap_content">

        <com.google.android.material.card.MaterialCardView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            app:cardBackgroundColor="@android:color/black">

            <!-- other views -->

        </com.google.android.material.card.MaterialCardView>

    </androidx.core.widget.NestedScrollView>

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

If I implement the MotionLayout like this, I will face another issue. The MaterialCardView height does not change when the user drags up the view, even if I set the height to match_parent:

Second MotionLayout

How can I change the code in a way that the red area covers the whole blue area?


Solution

  • Finally, I found the solution. I only need to add

    android:fillViewport="true"
    

    to the NestedScrollView to fix the issue. It happens because the height of NestedScrollView is bigger than its children in the end state, so I need to set fillViewport to true to resolve the issue.