滚动时为 RecyclerView 设置动画

Posted

技术标签:

【中文标题】滚动时为 RecyclerView 设置动画【英文标题】:Animate RecyclerView when scrolling 【发布时间】:2014-10-12 08:15:30 【问题描述】:

当我滚动 RecyclerView 时,有什么方法可以为它的元素设置动画吗?

我看了DefaultItemAnimatorRecyclerView.ItemAnimator,但动画似乎只有在数据集发生变化时才会被调用,如果我错了,请纠正我。

我对@9​​87654323@ 什么时候调用有点困惑?我在该类中设置了一些断点,但它们都没有停止我的应用程序。

但是回到我的问题,如何为 RecyclerView 设置动画?我希望某些元素具有另一种不透明度,这取决于一些自定义规则。


我做了更多的研究,似乎动画移动正是我正在寻找的。这些方法是从dispatchLayout() 调用的。这是该方法的javadoc:

layoutChildren() 的包装器,用于处理由布局引起的动画变化。 动画的工作假设有五种不同的项目 在玩: PERSISTENT:项目在布局前后可见 已移除:项目在布局之前可见并已被应用程序移除 添加:项目在布局之前不存在并且由应用程序添加 DISAPPEARING:项目之前/之后存在于数据集中,但从 在布局过程中可见到不可见(它们被移走 屏幕作为其他更改的副作用) 出现:项目之前/之后存在于数据集中,但从 在布局过程中不可见到可见(它们被移到 屏幕作为其他更改的副作用) 整体方法找出布局之前/之后存在哪些项目,以及 推断每个项目的上述五种状态之一。然后是动画 相应地设置: PERSISTENT 视图被移动(@link ItemAnimator#animateMove(ViewHolder, int, int, int, int)) REMOVED 视图被移除 (@link ItemAnimator#animateRemove(ViewHolder)) 添加了视图 (@link ItemAnimator#animateAdd(ViewHolder)) 消失的视图被移出屏幕 出现的视图在屏幕上移动

到目前为止,我正在寻找 PERSISTENT、DISAPPEARING 和 APPEARING,但由于这里的这一行,这些方法永远不会被调用:

boolean animateChangesSimple = mItemAnimator != null && mItemsAddedOrRemoved
            && !mItemsChanged;

mItemsAddedOrRemoved 总是假的,所以没有一个回调到达。知道如何正确设置设置标志吗?

【问题讨论】:

您可以使用 api11 中引入的 objectanimtor 对任何对象进行动画处理 很好,但是我怎么知道什么时候需要开始动画呢? 【参考方案1】:

我最终使用OnScrollListener 并以自定义animate() 方法对其进行动画处理。在我的情况下,该代码只需要 2 毫秒,因此对于 60 fps 来说没问题。

recyclerView.setOnScrollListener(new RecyclerView.OnScrollListener() 
    @Override
    public void onScrollStateChanged(int newState) 
        if(newState == RecyclerView.SCROLL_STATE_IDLE) 
            // special handler to avoid displaying half elements
            scrollToNext();
        
        animate();
    

    @Override
    public void onScrolled(int dx, int dy) 
        animate();
    
);

【讨论】:

你能添加更多代码吗?比如 scrollToNext ? 这超出了我的问题范围。你应该问一个独立的问题。请记住在实施时显示您当前的进度:) @rekire 你能帮我解决我的问题吗:***.com/questions/45858059/…【参考方案2】:

我是这样做的。可能会帮助某人。我不知道这是否是最好的方法,但对我来说效果很好。

更新: 要修复快速滚动行为,请覆盖适配器的 onViewDetachedFromWindow 方法并在动画视图上调用 clearAnimation(在本例中为 holder.itemView.clearAnimation() )。

up_from_bottom.xml

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
 android:shareInterpolator="@android:anim/decelerate_interpolator">
<translate
    android:fromXDelta="0%" android:toXDelta="0%"
    android:fromYDelta="100%" android:toYDelta="0%"
    android:duration="400" />
</set>

down_from_top.xml

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
 android:shareInterpolator="@android:anim/decelerate_interpolator">
<translate
    android:fromXDelta="0%" android:toXDelta="0%"
    android:fromYDelta="-100%" android:toYDelta="0%"
    android:duration="400" />
</set>

最后把这段代码放在onBindViewHolderrecyclerView 中。创建一个名为 lastPosition 的字段并将其初始化为 -1。

Animation animation = AnimationUtils.loadAnimation(context,
            (position > lastPosition) ? R.anim.up_from_bottom
                    : R.anim.down_from_top);
    holder.itemView.startAnimation(animation);
    lastPosition = position;

【讨论】:

notifiydatasetchange 时动画再次出现。有什么办法解决吗?【参考方案3】:

好的解决方案是在onBindViewHolder 方法中为适配器中的支架设置动画。 摘自 Material Test 项目 Slidenerd 的片段:

@Override 
public void onBindViewHolder(ViewHolderBoxOffice holder, int position) 
    Movie currentMovie = mListMovies.get(position);
    //one or more fields of the Movie object may be null since they are fetched from the web 
    holder.movieTitle.setText(currentMovie.getTitle());


    //retrieved date may be null 
    Date movieReleaseDate = currentMovie.getReleaseDateTheater();
    if (movieReleaseDate != null) 
        String formattedDate = mFormatter.format(movieReleaseDate);
        holder.movieReleaseDate.setText(formattedDate);
     else  
        holder.movieReleaseDate.setText(Constants.NA);
     


    int audienceScore = currentMovie.getAudienceScore();
    if (audienceScore == -1) 
        holder.movieAudienceScore.setRating(0.0F);
        holder.movieAudienceScore.setAlpha(0.5F);
     else  
        holder.movieAudienceScore.setRating(audienceScore / 20.0F);
        holder.movieAudienceScore.setAlpha(1.0F);
     


    if (position > mPreviousPosition) 
        AnimationUtils.animateSunblind(holder, true);         
     else  
        AnimationUtils.animateSunblind(holder, false);

     
    mPreviousPosition = position;

这是link

【讨论】:

此解决方案适用于某个库,并非适用于所有人。

以上是关于滚动时为 RecyclerView 设置动画的主要内容,如果未能解决你的问题,请参考以下文章

UICollectionVIew:在滚动时为单元格设置动画

UICollectionVIew:在视图滚动时为单元格设置动画

滚动时如何为 recyclerview 项目设置动画?

javascript [在页面滚动上设置动画粘贴CTA]这将在滚动时为点击元素设置动画,并在用户点击时将其关闭。 #javascript #css #sitewre

javascript [在页面滚动上设置动画粘贴CTA]这将在滚动时为点击元素设置动画,并在用户点击时将其关闭。 #javascript #css #sitewre

到达 HTML 文件中的某个点时为数字和文本设置动画