skip to Main Content

I have a motion layout that moves back and forth between covering the element below it, and showing it when it is swiped up, this element (the dashboard) has a swipe up image on it that lets the user know it’s swipable. The problem here is that I want the "swipe up arrow" to disappear after getting swiped.

But I’m faced with several problems: the motion layout doesn’t recognize elements other than the one below it, so it seems that a motion layout can’t do transitions for more than one element.

  • So I can’t use the dashboard motion layout to hide the swipe up image after the swipe, I tried and I it didn’t work and never gave me an error

  • I can’t turn the swipe up image into a motion layout either because it won’t recognize the dashboard

So I thought I would do it programmatically. Whenever the dashboard (the one in black) element is swiped up, the swipe up image is set to invisible, but having started to set that up, the dashboard element now ignores the swipe up listener from the motion layout and acknowledges the kotlin listener.

I can only think of several solutions, being a new android dev. One of which is adding a swipe up listener to the dashboard programmatically and using that to transition it upwards and get the arrow to disappear OR find a way to get the motion layout to transition the dashboard upward and remove the swipe up image once its been swiped

Neither of which is something I know how to do, I’m also open to more efficient alternatives

How it looks before its been swiped

How it should look after

main activity:

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/white"
tools:context=".MainActivity">

    <androidx.constraintlayout.widget.ConstraintLayout
        android:layout_width="match_parent"
        android:layout_height="500dp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent">

        <androidx.cardview.widget.CardView
            android:id="@+id/dashboard"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            app:cardBackgroundColor="@color/green"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent">

        </androidx.cardview.widget.CardView>
    </androidx.constraintlayout.widget.ConstraintLayout>

    <androidx.constraintlayout.motion.widget.MotionLayout
        android:id="@+id/constraintLayout12"
        android:layout_width="match_parent"
        android:layout_height="100dp"
        android:elevation="20dp"
        app:layoutDescription="@xml/activity_main_light_copy_2_xml_constraintlayout12_scene"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent">

        <ImageView
            android:id="@+id/swipeUpPic"
            android:layout_width="match_parent"
            android:layout_height="100dp"
            app:layout_constraintBottom_toBottomOf="@id/dashboard"
            app:layout_constraintEnd_toEndOf="@id/dashboard"
            app:layout_constraintStart_toStartOf="@id/dashboard"
            app:srcCompat="@drawable/scroll_image" />
    </androidx.constraintlayout.motion.widget.MotionLayout>

</androidx.constraintlayout.widget.ConstraintLayout>

Motion layout:

<?xml version="1.0" encoding="utf-8"?>
<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="1000">

        <OnSwipe
            motion:touchAnchorId="@id/dashboard"
            motion:dragDirection="dragUp"
            motion:touchAnchorSide="top" />

    </Transition>

    <ConstraintSet android:id="@+id/start">
        <Constraint
            android:id="@id/dashboard"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            motion:layout_constraintEnd_toEndOf="parent"
            motion:layout_constraintStart_toStartOf="parent" >
        </Constraint>

        <Constraint
            android:id="@id/swipeUpPic"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:visibility="visible"
            motion:layout_constraintEnd_toEndOf="parent"
            motion:layout_constraintStart_toStartOf="parent" >
        </Constraint>

    </ConstraintSet>

    <ConstraintSet android:id="@+id/end">
        <Constraint
            android:id="@id/dashboard"
            android:layout_width="match_parent"
            android:layout_height="400dp"
            motion:layout_constraintEnd_toEndOf="parent"
            motion:layout_constraintStart_toStartOf="parent" >
        </Constraint>

        <Constraint
            android:id="@id/swipeUpPic"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            motion:layout_constraintEnd_toEndOf="parent"
            motion:layout_constraintStart_toStartOf="parent"
            android:visibility="invisible">
        </Constraint>
    </ConstraintSet>
</MotionScene>

2

Answers


  1. There a few ways to achieve this.

    1. Design it flat (do not nest Views)
    2. Nested MotionLayout
    3. Build a Custom ViewGroup (along the lines of what you tried to do)

    The easiest is to simply design it flat. It is a little tricky to figure out how to make a virtual panel. The order of views in a MotionLayout is the z order(Bottom first). Playing around with it you can work it out.
    You may not want to do that for team/architecture reasons. e.g. One panel is being recused across several screens.

    2 and 3 are just variants of each other.
    The idea is the ViewGroup subclass listens to setProgress(float x) and the controlling motionLayout calls setProgress at the correct point.

    MotionLayout already listens to setProgress so some of it is done for you.

    The key is the outer MotionLayout panel is in Control of the Swipe.

    I would also recommend looking at a few examples:
    https://developer.android.com/training/constraint-layout/motionlayout/examples

    Login or Signup to reply.
  2. Let me start by saying, I totally agree with @hoford.

    The best approach would be to flatten your MotionLayout, however you can show/hide your swipe up button by adding a TransitionListener to your MotionLayout. Use addTransitionListener()

    You can either use:

    • onTransitionStarted()
      Called when a drawer is about to start a transition. Note. startId may be -1 if starting from an "undefined state". The startId and endId refers to the ConstraintSet ids.
    • onTransitionChange()
      Called when a drawer’s position changes. Where you can even track the current (transition) progress and apply the same transition state to your own View(s).
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search