如何动画RecyclerView项目时,他们出现

我怎么能动画回收视图项目时出现?

默认的项目动画器只在设置完回收器数据后添加或删除数据时才会动画。我是新开发的应用程序,不知道从哪里开始。

有什么想法可以实现吗?

319117 次浏览

编辑:

根据 ItemAnimator文档:

该类定义当对适配器进行更改时在项上发生的动画。

因此,除非你将你的项目一个一个地添加到你的RecyclerView中,并在每次迭代时刷新视图,否则我不认为ItemAnimator是你需要的解决方案。

下面是如何在RecyclerView项出现时使用CustomAdapter进行动画处理:

public class CustomAdapter extends RecyclerView.Adapter<CustomAdapter.ViewHolder>
{
private Context context;


// The items to display in your RecyclerView
private ArrayList<String> items;
// Allows to remember the last item shown on screen
private int lastPosition = -1;


public static class ViewHolder extends RecyclerView.ViewHolder
{
TextView text;
// You need to retrieve the container (ie the root ViewGroup from your custom_item_layout)
// It's the view that will be animated
FrameLayout container;


public ViewHolder(View itemView)
{
super(itemView);
container = (FrameLayout) itemView.findViewById(R.id.item_layout_container);
text = (TextView) itemView.findViewById(R.id.item_layout_text);
}
}


public CustomAdapter(ArrayList<String> items, Context context)
{
this.items = items;
this.context = context;
}


@Override
public CustomAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType)
{
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.custom_item_layout, parent, false);
return new ViewHolder(v);
}


@Override
public void onBindViewHolder(ViewHolder holder, int position)
{
holder.text.setText(items.get(position));


// Here you apply the animation when the view is bound
setAnimation(holder.itemView, position);
}


/**
* Here is the key method to apply the animation
*/
private void setAnimation(View viewToAnimate, int position)
{
// If the bound view wasn't previously displayed on screen, it's animated
if (position > lastPosition)
{
Animation animation = AnimationUtils.loadAnimation(context, android.R.anim.slide_in_left);
viewToAnimate.startAnimation(animation);
lastPosition = position;
}
}
}

你的custom_item_layout看起来像这样:

<FrameLayout
android:id="@+id/item_layout_container"
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content">


<TextView
android:id="@+id/item_layout_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceListItemSmall"
android:gravity="center_vertical"
android:minHeight="?android:attr/listPreferredItemHeightSmall"/>


</FrameLayout>

有关CustomAdapters和RecyclerView的更多信息,请参阅此培训关于官方文档

快速滚动的问题

使用这种方法可能会导致快速滚动的问题。视图可以在动画发生时被重用。为了避免这种情况,建议在分离动画时清除动画。

    @Override
public void onViewDetachedFromWindow(final RecyclerView.ViewHolder holder)
{
((CustomViewHolder)holder).clearAnimation();
}

CustomViewHolder:

    public void clearAnimation()
{
mRootLayout.clearAnimation();
}

旧答案:

看看Gabriele Mariotti的回购,我很确定你会找到你需要的东西。他为RecyclerView提供了简单的itemanimator,如SlideInItemAnimator或SlideScaleItemAnimator。

一个好的开始是这样的: https://github.com/wasabeef/recyclerview-animators/blob/master/animators/src/main/java/jp/wasabeef/recyclerview/adapters/AnimationAdapter.java < / p > 你甚至不需要整个库,那个类就足够了。 然后,如果你实现你的Adapter类,给出一个这样的动画器:

@Override
protected Animator[] getAnimators(View view) {
return new Animator[]{
ObjectAnimator.ofFloat(view, "translationY", view.getMeasuredHeight(), 0)
};
}


@Override
public long getItemId(final int position) {
return getWrappedAdapter().getItemId(position);
}

你会看到项目滚动时从底部出现,也避免了快速滚动的问题。

当项目被绑定到适配器中时,在recyclerview中进行动画可能不是最好的想法,因为这会导致recyclerview中的项目以不同的速度进行动画。在我的例子中,在recyclerview的末尾的项目动画到他们的位置比顶部的更快,因为顶部的那些有进一步的旅行,所以它看起来不整洁。

我用来动画每个项目到recyclerview的原始代码可以在这里找到:

< a href = " http://frogermcs.github。io / Instagram-with-Material-Design-concept-is-getting-real noreferrer“rel = > http://frogermcs.github.io/Instagram-with-Material-Design-concept-is-getting-real/ < / >

但是我会复制粘贴代码以防链接中断。

步骤1:在onCreate方法中设置此值,以确保动画只运行一次:

if (savedInstanceState == null) {
pendingIntroAnimation = true;
}

你需要把这段代码放入你想要开始动画的方法中:

if (pendingIntroAnimation) {
pendingIntroAnimation = false;
startIntroAnimation();
}

在链接中,作者是动画工具栏图标,所以他把它放在这个方法中:

@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.menu_main, menu);
inboxMenuItem = menu.findItem(R.id.action_inbox);
inboxMenuItem.setActionView(R.layout.menu_item_view);
if (pendingIntroAnimation) {
pendingIntroAnimation = false;
startIntroAnimation();
}
return true;
}

步骤3:现在编写startIntroAnimation()的逻辑:

private static final int ANIM_DURATION_TOOLBAR = 300;


private void startIntroAnimation() {
btnCreate.setTranslationY(2 * getResources().getDimensionPixelOffset(R.dimen.btn_fab_size));


int actionbarSize = Utils.dpToPx(56);
toolbar.setTranslationY(-actionbarSize);
ivLogo.setTranslationY(-actionbarSize);
inboxMenuItem.getActionView().setTranslationY(-actionbarSize);


toolbar.animate()
.translationY(0)
.setDuration(ANIM_DURATION_TOOLBAR)
.setStartDelay(300);
ivLogo.animate()
.translationY(0)
.setDuration(ANIM_DURATION_TOOLBAR)
.setStartDelay(400);
inboxMenuItem.getActionView().animate()
.translationY(0)
.setDuration(ANIM_DURATION_TOOLBAR)
.setStartDelay(500)
.setListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
startContentAnimation();
}
})
.start();
}

我更倾向于:

我宁愿动画整个recyclerview,而不是在recyclerview内的项目。

步骤1和2保持不变。

在第3步,只要你的API调用返回你的数据,我将开始动画。

private void startIntroAnimation() {
recyclerview.setTranslationY(latestPostRecyclerview.getHeight());
recyclerview.setAlpha(0f);
recyclerview.animate()
.translationY(0)
.setDuration(400)
.alpha(1f)
.setInterpolator(new AccelerateDecelerateInterpolator())
.start();
}

这将使您的整个recyclerview动画,以便它从屏幕底部飞进来。

Recyclerview项第一次出现时,我对它们进行动画淡出,如下面的代码所示。也许这对某人有用。

private final static int FADE_DURATION = 1000; //FADE_DURATION in milliseconds


@Override
public void onBindViewHolder(ViewHolder holder, int position) {


holder.getTextView().setText("some text");


// Set the view to fade in
setFadeAnimation(holder.itemView);
}


private void setFadeAnimation(View view) {
AlphaAnimation anim = new AlphaAnimation(0.0f, 1.0f);
anim.setDuration(FADE_DURATION);
view.startAnimation(anim);
}

你也可以用下面的setScaleAnimation()替换setFadeAnimation(),通过从一点缩放来动画项目的外观:

private void setScaleAnimation(View view) {
ScaleAnimation anim = new ScaleAnimation(0.0f, 1.0f, 0.0f, 1.0f, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
anim.setDuration(FADE_DURATION);
view.startAnimation(anim);
}

上面的代码有一些缺陷,当你滚动RecyclerView项总是褪色或缩放。如果你愿意,你可以添加代码,只允许动画在包含RecyclerView的片段或活动第一次创建时发生(例如,在创建时获得系统时间,只允许动画在第一个FADE_DURATION毫秒)。

我从pbm的回答中创建了一个带有少量modification的动画,以使动画只运行一次

换句话说Animation appear with you scroll down only

private int lastPosition = -1;


private void setAnimation(View viewToAnimate, int position) {
// If the bound view wasn't previously displayed on screen, it's animated
if (position > lastPosition) {
ScaleAnimation anim = new ScaleAnimation(0.0f, 1.0f, 0.0f, 1.0f, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
anim.setDuration(new Random().nextInt(501));//to make duration random number between [0,501)
viewToAnimate.startAnimation(anim);
lastPosition = position;
}
}

并在onBindViewHolder中调用该函数

@Override
public void onBindViewHolder(ViewHolder holder, int position) {


holder.getTextView().setText("some text");


// call Animation function
setAnimation(holder.itemView, position);
}

就像下面那样扩展你的适配器

public class RankingAdapter extends AnimatedRecyclerView<RankingAdapter.ViewHolder>

并添加super方法到onBindViewHolder

@Override
public void onBindViewHolder(ViewHolder holder, final int position) {
super.onBindViewHolder(holder, position);

这是一种自动创建动画适配器的方法比如Basheer AL-MOMANI

import android.support.v7.widget.RecyclerView;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.Animation;
import android.view.animation.ScaleAnimation;


import java.util.Random;


/**
* Created by eliaszkubala on 24.02.2017.
*/
public class AnimatedRecyclerView<T extends RecyclerView.ViewHolder> extends RecyclerView.Adapter<T> {




@Override
public T onCreateViewHolder(ViewGroup parent, int viewType) {
return null;
}


@Override
public void onBindViewHolder(T holder, int position) {
setAnimation(holder.itemView, position);
}


@Override
public int getItemCount() {
return 0;
}


protected int mLastPosition = -1;


protected void setAnimation(View viewToAnimate, int position) {
if (position > mLastPosition) {
ScaleAnimation anim = new ScaleAnimation(0.0f, 1.0f, 0.0f, 1.0f, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
anim.setDuration(new Random().nextInt(501));//to make duration random number between [0,501)
viewToAnimate.startAnimation(anim);
mLastPosition = position;
}
}


}

在你的recyclerview适配器中创建这个方法

private void setZoomInAnimation(View view) {
Animation zoomIn = AnimationUtils.loadAnimation(context, R.anim.zoomin);// animation file
view.startAnimation(zoomIn);
}

最后在< em > onBindViewHolder < / em >中添加这行代码

setZoomInAnimation(holder.itemView);

你可以像这样给RecyclerView添加一个android:layoutAnimation="@anim/rv_item_animation"属性:

<android.support.v7.widget.RecyclerView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layoutAnimation="@anim/layout_animation_fall_down"
/>

感谢这里的优秀文章: https://proandroiddev.com/enter-animation-using-recyclerview-and-layoutanimation-part-1-list-75a874a5d213 < / p >

只用XML简化

访问Gist链接

res /动物/ layout_animation.xml

<?xml version="1.0" encoding="utf-8"?>
<layoutAnimation xmlns:android="http://schemas.android.com/apk/res/android"
android:animation="@anim/item_animation_fall_down"
android:animationOrder="normal"
android:delay="15%" />

res /动物/ item_animation_fall_down.xml

<set xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="500">


<translate
android:fromYDelta="-20%"
android:toYDelta="0"
android:interpolator="@android:anim/decelerate_interpolator"
/>


<alpha
android:fromAlpha="0"
android:toAlpha="1"
android:interpolator="@android:anim/decelerate_interpolator"
/>


<scale
android:fromXScale="105%"
android:fromYScale="105%"
android:toXScale="100%"
android:toYScale="100%"
android:pivotX="50%"
android:pivotY="50%"
android:interpolator="@android:anim/decelerate_interpolator"
/>


</set>

在布局和循环视图中使用:

<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recycler_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layoutAnimation="@anim/layout_animation"
app:layout_behavior="@string/appbar_scrolling_view_behavior" />
< p > 2019年, 我建议把所有的项目动画放到ItemAnimator中

让我们从在循环视图中声明动画器开始:

with(view.recycler_view) {
adapter = Adapter()
itemAnimator = CustomAnimator()
}

然后声明自定义动画器,

class CustomAnimator() : DefaultItemAnimator() {


override fun animateAppearance(
holder: RecyclerView.ViewHolder,
preInfo: ItemHolderInfo?,
postInfo: ItemHolderInfo): Boolean{} // declare  what happens when a item appears on the recycler view


override fun animatePersistence(
holder: RecyclerView.ViewHolder,
preInfo: ItemHolderInfo,
postInfo: ItemHolderInfo): Boolean {} // declare animation for items that persist in a recycler view even when the items change


}

与上面的类似,还有一个用于消失animateDisappearance,用于添加animateAdd,用于更改animateChange和移动animateMove

重要的一点是在它们内部调用正确的动画调度器。

我认为,这样使用更好:(在RecyclerView 适配器中只覆盖一个方法)

override fun onViewAttachedToWindow(holder: ViewHolder) {
super.onViewAttachedToWindow(holder)


setBindAnimation(holder)
}

如果你想在RV中添加每个动画。