0

Basically, I have a MotionLayout with a RecyclerView and an ImageView inside. I want the ImageView to act as a header for the RecyclerView and move out of the view when scrolling down the recycler view.

Currently, I have the motion layout making the imageview invisible while the user scrolls down and makes the margin above the recyclerview reduce to 0dp, which is what I want. However, scrolling back up reverses the animation automatically, regardless of position in the recycler view, causing the margin and image to reappear and hiding the contents of the recycler view until the reverse of the animation is completed. I only want the margin/image to reappear above the first item in the recycler view. You can see this in the GIF below that the margin causes the first item to be cut off if it is initially scrolled out of view.

I've been trying to play with the OnSwipe attributes but I've had no luck.

Here is my code:

MotionLayout:

<?xml version="1.0" encoding="utf-8"?>
<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:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="?attr/theme_background"
    app:layoutDescription="@xml/fragment_scene"
    tools:context=".App.Fragment">

    <Button
        android:id="@+id/button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="10dp"
        android:elevation="2dp"
        android:text="BACK TO TOP"
        android:visibility="invisible"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.5"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        tools:visibility="visible" />

    <ImageView
        android:id="@+id/image_view"
        android:layout_width="match_parent"
        android:layout_height="300dp"
        android:elevation="1dp"
        android:scaleType="centerCrop"
        tools:src="@tools:sample/backgrounds/scenic"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toEndOf="parent"/>

    <Space
        android:id="@+id/spacer"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_marginTop="250dp"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/recyclerview"
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:elevation="1dp"
        android:clipToPadding="false"
        android:paddingBottom="?actionBarSize"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintTop_toBottomOf="@id/spacer" />


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

MotionScene

<?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:dragDirection="dragUp"
            motion:dragScale="1"
            motion:moveWhenScrollAtTop="false"
            motion:onTouchUp="stop"
            motion:touchAnchorId="@id/recyclerview"
            motion:touchAnchorSide="top"/>
    </Transition>

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

    <ConstraintSet android:id="@+id/end">
        <Constraint
            android:id="@+id/image_view"
            android:elevation="1dp"
            motion:layout_constraintEnd_toEndOf="parent"
            android:layout_width="match_parent"
            android:layout_height="300dp"
            motion:layout_constraintTop_toTopOf="parent"
            motion:layout_constraintStart_toStartOf="parent"
            android:visibility="invisible" />
        <Constraint
            motion:layout_constraintEnd_toEndOf="parent"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            motion:layout_constraintTop_toTopOf="parent"
            motion:layout_constraintStart_toStartOf="parent"
            android:layout_marginTop="0dp"
            android:id="@+id/spacer" />
    </ConstraintSet>
</MotionScene>

BTW I'm using androidx.constraintlayout:constraintlayout:2.1.0-beta02 for MotionLayout

Demonstration of Problem

Edit: Showing how app behaves with motion:moveWhenScrollAtTop="true"

enter image description here

Don Robin
  • 121
  • 2
  • 16
  • 1
    motion:moveWhenScrollAtTop="false" What is the difference when you set this to true? – hoford May 30 '21 at 20:53
  • @hoford when setting that to true I found that the animation remains in the "start" state of the motion layout until I scroll to the end of the recyclerview. Upon reaching the end, it immediately switches to the "end" state and remains that way until I scroll to the top of the recyclerview again. Interestingly, I found a tutorial online that set that to true and it worked for [them](https://www.youtube.com/watch?v=8qsJACuf4xA) but even with everything the same as that tutorial, I still couldn't get it to work. – Don Robin May 30 '21 at 23:11
  • It should work with true. Post a video of what you see when set to true. The video for false is working as expected. (Typically is a panel. – hoford May 31 '21 at 18:26
  • @hoford Please see edit in original post – Don Robin May 31 '21 at 22:09
  • Thanks, I copied your layout & motionScean (hard coding my onw picture etc.) put it up (in onCreate(...). It works. Something else in your system is affecting the layout. I recommend starting form a simplified versions, launched from a temporary mainActivity. See if that works for you. Then add back what ever you are doing. I do notice @id/button which should stay invisible but is not. Programmatic manipulation of objects within MotionLayout can have odd effects. (Google "motionlayout visibility") – hoford Jun 01 '21 at 00:59
  • At least I know it works on your end. Thanks for the suggestion, I'll give that a try. – Don Robin Jun 01 '21 at 22:46

0 Answers0