0

I'm animating my recycler view so that it slides side-to-side, exposing a checkbox on the left. The initial animation is great, but when the list is longer than the device height, we get issues with where the two elements (the date and the horizontal rule) are placed. I've recorded two videos to demonstrate the bug in more detail.

Goal: How do I prevent the dates from zig-zagging like that?

http://dai.ly/x6j70qz

http://dai.ly/x6j70yr

Here's the parent recycler view:

<android.support.v7.widget.RecyclerView
        android:id="@+id/recyclerview_vins"
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:paddingStart="-46dp"
        android:visibility="visible"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

And here's the view holder for each list item:

<android.support.constraint.ConstraintLayout 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/front_layout_read_mode"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">

    <CheckBox
        android:id="@+id/is_selected_checkbox"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginEnd="8dp"
        android:button="@drawable/checkbox_selector"
        android:checked="false"
        android:scaleX="0.5"
        android:scaleY="0.5"
        app:layout_constraintEnd_toStartOf="@+id/year_make_model_text_view"
        app:layout_constraintTop_toTopOf="@+id/year_make_model_text_view" />

    <TextView
        android:id="@+id/year_make_model_text_view"
        style="@style/VinListYearMakeModel"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_marginEnd="8dp"
        android:layout_marginStart="64dp"
        android:layout_marginTop="24dp"
        app:layout_constraintEnd_toStartOf="@+id/date_text_view"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        tools:text="1998 Honda Fit blahblahblahblahblahblahblahblahblahblahblah" />

    <TextView
        android:id="@+id/vin_text_view"
        style="@style/VinListVin"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textAllCaps="false"
        app:layout_constraintStart_toStartOf="@+id/year_make_model_text_view"
        app:layout_constraintTop_toBottomOf="@+id/year_make_model_text_view"
        tools:text="4JHG2J43HJHG34" />

    <TextView
        android:id="@+id/date_text_view"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginEnd="16dp"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintTop_toTopOf="@+id/year_make_model_text_view"
        tools:text="03/14/18" />

    <TextView
        android:id="@+id/horizontal_rule"
        android:layout_width="0dp"
        android:layout_height="1dp"
        android:layout_marginTop="24dp"
        android:background="#E1E1E1"
        android:textSize="20sp"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/vin_text_view" />
</android.support.constraint.ConstraintLayout>

And here's the gist of the animation that slides the recycler view side-to-side:

val aul = AnimatorUpdateListener {
    Log.i("Animated Value", it.animatedValue.toString())
    recyclerview_vins.setPadding(it.animatedValue as Int, 0 ,0 ,0)
}
val varl = ValueAnimator.ofInt(0, -137) // These values reversed for opposite animation
varl.duration = 400
varl.addUpdateListener(aul)
varl.start()

enter image description here

I think it may be related to other bugs having to do with the last item in a recycler view list behaving weirdly:

Weird Animation Comes For RecyclerView Last Item

Miguel Valencia
  • 221
  • 3
  • 14

1 Answers1

1

When you using recyclerviews you have to keep in mind that the VIEWS are recycled. this means as you scroll the same view is brought onto screen that previously left the screen.

So if you just scroll without ever sliding anything, it will probably be fine, but the second you animate a view into a different position, that view will stay there for the next active data item that will populate it with it's content.

You need to make sure that as onBindView happens that you are clearing the animations and cleaning up your previous movement of the view. Otherwise, it will stay selected, slide, or whatever else you did to the view.

If you are using animations, you can simply use UIElementThatYouUsed.clearAnimations() or something like that, and it should remove whatever you animated over.

I've had very similar issues in the past when animating recycler view rows, they do remain where you move them unless you clear it.

Sam
  • 5,342
  • 1
  • 23
  • 39
  • Thanks for the advice. I have two versions of my list––one where I animate the RecyclerView itself from within the fragment, and another where I animate the elements of the list during `bind` (I do that by checking whether we're in EDIT mode). I tried running `clearAnimation()` on each list item element during the bind event. No luck there. And I'm not sure where I would run `clearAnimation()` on the RecyclerView itself. I think I'm still misunderstanding something about your point. Here's another video showing off a little more, and trying to understand your point: http://dai.ly/x6j74uy – Miguel Valencia May 09 '18 at 20:27
  • well that can get tricky especially during a fling event. You need to have animation listener call backs for complete to know that it completed and be able to cancel that animation or clear it if it leaves the screen prematurely. So you are going to have to do some management to keep track in a viewholder pattern that will know if the animation completed or not and if you are able to clear it before you start the next one. This is all Asynchronous so you will have to make sure you are properly handling it. You can test it by putting scrolling slowly and adequately clearing the previous – Sam May 09 '18 at 20:39
  • before starting the next one, you could test this by doing a delay handler of 500ms on each bind row before starting the new animation giving adequate time to clear previous. That would not be your fix, but it would help you identify async issues in clearing animations vs starting the next one. Hope that helps – Sam May 09 '18 at 20:40