RecyclerView项目动画列表填充,但第一个项目都在同一时间动画,只是看起来像一个延迟



我已经实现了这个问题中显示的方法,滚动上的动画看起来非常好。然而,最初的列表填充动画只是显示所有对象同时出现在屏幕上,这看起来就像一个延迟。

在调试时,我可以看到动画方法被调用了7次,但我猜它是如此之快,以至于它们都试图在基本相同的时间运行。你知道我该怎么做吗?我试过延迟动画播放,但我不知道该怎么做。我在这里问了这个问题。谢谢你的帮助!

编辑:我可以张贴相同的代码,我放在另一个问题:

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

然后是SetAnimation方法

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;
        }
    }

这里我真正想要的是动画在lastposition = position行被调用之前完成。

和空AnimationListener,因为我真的不确定如何处理等待。

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

我必须做一些类似的事情。基本上,我采取的方法是,每当我开始动画时,我也会根据动画的最后一次启动时间通知最小开始时间。

由于你没有发布任何代码,我将写一个我所做的基本大纲:

// 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;
}

吉尔的回答给了我正确的方向,但由于我正在与Xamarin合作。在Android上,我需要做一些不同的事情。我在StartOffset中使用了他的想法,因为c#不使用匿名类(使可运行程序变得相当困难)。这是我最终的动画代码(在处理了延迟之后)。

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;
    }

然后我在类的顶部定义并初始化了这些变量:

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

这个方法在OnBindViewHolder结束时被调用。现在,OnBindViewHolder第一次被调用时它会经过else语句。我必须在这里设置一个初始延迟,否则动画似乎在屏幕上开始了一半,看起来很糟糕。这个延迟还可以确保项目在快速滚动时按顺序动画。

我仍然有一个问题,如果用户在加载视图时立即滚动。初始项保持它们的延迟,但是第一个在滚动时设置为动画的项可能会在第一个项完成之前开始动画。

最新更新