Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Bottom sheet + Android MotionLayout implementation

I am trying to implement Bottom sheet using MotionLayout. It works in a trivial case - when bottom sheet should be visible only in a half of screen (for example). But I can't make it work in a scenario when bottom sheet expands and fills whole screen.

enter image description here

So here can be 3 states:

  1. Bottom sheet hidden
  2. Bottom sheet fills half screen
  3. Bottom sheet fills whole screen

Here is layout:

<androidx.constraintlayout.motion.widget.MotionLayout
       android:layout_width="match_parent"
       android:layout_height="match_parent"
       app:layoutDescription="@xml/scene_description">

         <FrameLayout
            android:id="@+id/fragmentPlaceholder"
            android:layout_width="match_parent"
            android:layout_height="570dp"
            android:elevation="8dp"> some content here </FrameLayout>


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

Here 570dp is equal to half screen (for example)

And the content of scene_description.xml:

<?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
        android:id="@+id/transition1"
        app:constraintSetStart="@id/bottomSheetHidden"
        app:constraintSetEnd="@id/bottomSheetHalfOpen"
        app:duration="300">

        <OnSwipe
            app:dragDirection="dragDown"
            app:onTouchUp="autoCompleteToStart"
            app:touchAnchorId="@+id/fragmentPlaceholder"
            app:touchAnchorSide="bottom"/>

    </Transition>


    <Transition
        android:id="@+id/transition2"
        app:constraintSetStart="@id/bottomSheetHalfOpen"
        app:constraintSetEnd="@id/bottomSheetOpenFullScreen"
        app:duration="300">

    </Transition>


    <Transition
        android:id="@+id/transition3"
        app:constraintSetStart="@id/bottomSheetHidden"
        app:constraintSetEnd="@id/bottomSheetOpenFullScreen"
        app:duration="300">

        <OnSwipe
            app:dragDirection="dragDown"
            app:touchAnchorId="@+id/fragmentPlaceholder"
            app:touchAnchorSide="bottom" />

    </Transition>


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

        <Constraint android:id="@id/fragmentPlaceholder">
            <Layout
                android:layout_width="match_parent"
                android:layout_height="570dp"
                app:layout_constraintStart_toStartOf="parent"
                app:layout_constraintEnd_toEndOf="parent"
                app:layout_constraintTop_toBottomOf="parent"/> <!-- below screen, not visible-->
        </Constraint>

    </ConstraintSet>


    <ConstraintSet android:id="@+id/bottomSheetHalfOpen"
        app:deriveConstraintsFrom="@id/bottomSheetHidden">

        <Constraint android:id="@id/fragmentPlaceholder">
            <Layout
                android:layout_width="match_parent"
                android:layout_height="570dp"
                app:layout_constraintStart_toStartOf="parent"
                app:layout_constraintEnd_toEndOf="parent"
                app:layout_constraintBottom_toBottomOf="parent" />
        </Constraint>
    </ConstraintSet>


    <ConstraintSet android:id="@+id/bottomSheetOpenFullScreen"
        app:deriveConstraintsFrom="@id/bottomSheetHidden">

        <Constraint android:id="@id/fragmentPlaceholder">
            <Layout
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:layout_marginTop="30dp"
                app:layout_constraintTop_toTopOf="parent"
                app:layout_constraintStart_toStartOf="parent"
                app:layout_constraintEnd_toEndOf="parent"
                app:layout_constraintBottom_toBottomOf="parent" />
        </Constraint>

    </ConstraintSet>

</MotionScene>


The problems is OnSwipe doesn't work when bottom sheet is in Full screen state, but works when bottom sheet is in half screen state. I want to have an opportunity to hide bottom sheet using swipe movement.

How this problem could be solved? Should transitions be added or modified?

like image 481
Ildar Zaripov Avatar asked Jun 15 '20 16:06

Ildar Zaripov


People also ask

How do you implement a bottom sheet?

Approach: Add the support Library in build. gradle file and add dependency in the dependencies section. With the help of this library we can inherit the BottomSheetDialogFragment which helps us to implement Bottom Sheet component.

What is MotionLayout in Android?

MotionLayout is a layout type that helps you manage motion and widget animation in your app. MotionLayout is a subclass of ConstraintLayout and builds upon its rich layout capabilities. As part of the ConstraintLayout library, MotionLayout is available as a support library and is backwards-compatible to API level 14.

What is bottom sheet in Android?

Bottom Sheet dialogs seem to be replacing regular Android dialogs and menus. The Bottom Sheet is a component that slides up from the bottom of the screen to showcase additional content in your application. A Bottom Sheet dialog is like a message box triggered by the user's actions.


1 Answers

Your transitions just needed a little tweaking, constraints were fine:

  • You don't need a third transition. If you're swiping between different states in the same direction - or actually even if you change directions, MotionLayout takes care of cleanly moving through multiple onSwipe transitions.
  • Your second and third ConstraintSets do not actually change the position of the bottom edge of fragment you're moving, but you specified that the scene should calculate progress based on that edge relative to the swipe gesture. I recommend going through the MotionLayout codelab and specifically Lesson 9 which illustrates this concept really well. As a consequence I changed the touchAnchorSide to top.
  • duration means nothing to OnSwipe transitions, can just delete it
  • It really doesn't matter whether you use dragUp or dragDown, it ends up with the same vertical gesture-based animation. I think dragUp is a little more understandable in this case.

Modified transitions:

    <Transition
        android:id="@+id/transition1"
        app:constraintSetStart="@id/bottomSheetHidden"
        app:constraintSetEnd="@id/bottomSheetHalfOpen">

        <OnSwipe
            app:dragDirection="dragUp"
            app:onTouchUp="autoCompleteToStart"
            app:touchAnchorId="@+id/fragmentPlaceholder"
            app:touchAnchorSide="top"/>

    </Transition>

    <Transition
        android:id="@+id/transition2"
        app:constraintSetStart="@id/bottomSheetHalfOpen"
        app:constraintSetEnd="@id/bottomSheetOpenFullScreen">

        <OnSwipe
            app:dragDirection="dragUp"
            app:touchAnchorId="@+id/fragmentPlaceholder"
            app:touchAnchorSide="top" />

    </Transition>
like image 113
Jason Pearson Avatar answered Oct 25 '22 18:10

Jason Pearson