RecyclerView项目在列表填充上设置动画,但是第一个项目同时具有动画效果,只是看起来像滞后

时间:2016-08-10 07:51:55

标签: android xamarin.android android-recyclerview android-animation

我已经实现了显示in this question的方法,滚动动画看起来非常精细。但是,初始列表填充动画只显示屏幕上同时出现的所有对象,它看起来就像是滞后。

在调试时,我可以看到动画方法被调用了7次,但我猜它是如此之快,以至于它们都试图在基本相同的时间运行。任何想法我能做什么?我试图推迟动画,但我不知道如何做到这一点。我问过这个问题here.谢谢你的帮助!

编辑:我可以发布与其他问题相同的代码:

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

我真正想要的是在调用lastPostion =位置线之前完成动画。

空的AnimationListener,因为我真的不知道如何处理等待。

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

        }

        public void OnAnimationRepeat(Animation animation)
        {

        }

        public void OnAnimationStart(Animation animation)
        {

        }
    }

2 个答案:

答案 0 :(得分:0)

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

由于您没有发布任何代码,我将写下我所做的基本概述:

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

希望这很清楚,并帮助你开始。

答案 1 :(得分:0)

Gil的回答让我朝着正确的方向前进,但由于我正在使用Xamarin.Android,我需要做一些不同的事情。我将他的想法用于StartOffset,因为C#不使用匿名类(使runnables变得更加困难)。这是我的最终动画代码(在播放延迟之后)。

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语句。我不得不在这里设置一个初始延迟,因为否则动画似乎开始在屏幕的一半,看起来很糟糕。此延迟还可确保项目在快速滚动时按顺序设置动画。

我仍然遇到的一个问题是用户在加载视图时是否立即滚动。初始项目保持延迟,但滚动到的第一个项目设置为动画可能会在第一个项目完成之前开始动画。我不知道如何解决这个问题...