1

I have implemented the method shown in this question and the animation on scroll looks perfectly fine. However, the initial list fill animation just shows all objects appear on the screen at the same time and it just looks like a lag.

While debugging, I can see that the animation method is being called 7 times, but I guess it is so fast that they are all trying to run at basically the same time. Any ideas what I can do? I tried delaying the animation, but I got stuck with how to do that. I asked that question here. Thank you for the help!

Edit: I can post the same code that I put on the other question:

public override void OnBindViewHolder(RecyclerView.ViewHolder holder, int position)
    {
        //Normal OnBindViewHolder stuff
        SetAnimation(vh.ItemView, position);
    }

And then the SetAnimation method:

private void SetAnimation(View viewToAnimate, int position)
    {
        if (position > lastPosition)
        {
            var animation = AnimationUtils.LoadAnimation(_context, Resource.Animation.up_from_bottom);
            //animation.SetAnimationListener(new CheckpointAnimationListener());
            viewToAnimate.StartAnimation(animation);
            lastPosition = position;
        }
    }

What I really want here is for the animation to finish before the lastPostion = position line is called.

And the empty AnimationListener, since I am really not sure how to handle the wait.

 private class CheckpointAnimationListener : Java.Lang.Object, Animation.IAnimationListener
    {
        public void OnAnimationEnd(Animation animation)
        {

        }

        public void OnAnimationRepeat(Animation animation)
        {

        }

        public void OnAnimationStart(Animation animation)
        {

        }
    }
Community
  • 1
  • 1
Jason Toms
  • 850
  • 2
  • 10
  • 23

2 Answers2

0

I had to do something similar. Basically, the approach I took was whenever I started an animation, I also informed when the minimum start time would be, based on the last time the animation was initiated.

Since you didn't post any code, I'll write a basic outline of what I did:

// member to know when the minimum start time of the next animation will be.
private long mNextAnimationStartTime;

...

public void onBindViewHolder(...) {
    // perform binding logic

    // sample the current time.
    long currentTime = System.currentTimeMillisec();

    // if the next animation time is greater than now...
    if (mNextAnimationStartTime > currentTime) {

        // calculate how much time to wait before showing the next animation. 
        int delay = mNextAnimationStartTime - currentTime;

        // In this example, I use postDelayed to postpone the animation, 
        // but you could also use start offset of the animation itself.
        postDelayed(new Runnable() {
            @Override
            public void run() {

                // start the animation after a delay.
                startAnimation(viewToAnimate);
            }
        }, delay);
    } else {

        // if the next animation time is in the past, just start the animation.
        startAnimation(viewToAnimate);
    }

    // schedule the next animation start time to now + 100 ms (play with this 100 to fit your needs)
    mNextAnimationStartTime = currentTime + 100;
}

Hope this was clear, and helps you get started.

Gil Moshayof
  • 16,633
  • 4
  • 47
  • 58
  • I copied my code from my previous question and put it in this one. But your code gives me a good idea of where to go :) I am working in Xamarin.Android so I need to do a few things differently, but your idea is a good one. – Jason Toms Aug 10 '16 at 08:12
0

The answer from Gil sent me in the right direction, but since I am working with Xamarin.Android I needed to do a couple of things differently. I used his idea for StartOffset instead, since C# does not use anonymous classes (making runnables quite a bit more difficult). Here is my final animation code (after playing around with the delays).

private void SetAnimation(View viewToAnimate, int position)
    {
        var animation = AnimationUtils.LoadAnimation(_context, Resource.Animation.up_from_bottom);

        _currentTime = JavaSystem.CurrentTimeMillis();

        long difference = _currentTime - _timeAtFirstCall;

        //this will cause the first items to populate the view to animate in order instead of at the same time.
        //_delay is increased each time so each item will start 75ms after the one before it.  difference is
        //there to make sure later items in the list dont get this delay and animate as they appear.
        if (_nextAnimationStartTime > _currentTime && difference < 150)
        {
            if (position > lastPosition)
            {
                animation.StartOffset = _delay;
                viewToAnimate.StartAnimation(animation);
                lastPosition = position;
                _delay += 75;
            }

        }
        else
        {
            if (position > lastPosition)
            {
                animation.StartOffset = 75;
                viewToAnimate.StartAnimation(animation);
                lastPosition = position;
            }
        }

        _nextAnimationStartTime = _currentTime + 400;

    }

And then I had these variables defined and initialized at the top of the class:

    private int lastPosition = -1;
    private long _nextAnimationStartTime = 0;
    private long _currentTime = 0;
    private long _timeAtFirstCall = JavaSystem.CurrentTimeMillis();
    private long _delay = 150;

This method is called at the end of OnBindViewHolder. So now, the first time OnBindViewHolder is called it goes through the else statement. I had to set an initial delay here as well because otherwise the animation seemed to start half way on the screen and just looked bad. This delay also ensures the items will animate in sequence on a fast scroll.

The one problem that I still have is if the user scrolls immediately when loading the view. The initial items keep their delay, but the first item that is set to animate when it is scrolled to might start its animation before the first items are finished. I am not sure how to get around this problem...

Jason Toms
  • 850
  • 2
  • 10
  • 23