web-dev-qa-db-ja.com

RecyclerView項目が表示されたときにアニメートする方法

出現時にRecyclerViewアイテムをアニメートするにはどうすればよいですか?

デフォルトのアイテムアニメーターは、リサイクラーデータの設定後にデータが追加または削除されたときにのみアニメートします。私は新しいアプリケーションを開発しているので、どこから始めればいいのかわかりません。

どのようにこれを達成するためのアイデアはありますか?

208
PaulNunezM

編集:

ItemAnimatorのドキュメント によると:

このクラスは、アダプタに変更が加えられたときにアイテムに発生するアニメーションを定義します。

そのため、アイテムを1つずつRecyclerViewに追加して、反復のたびにビューを更新しない限り、ItemAnimatorがあなたのニーズに対する解決策ではないと思います。

CustomAdapterを使用して表示されるRecyclerView項目をアニメートする方法は次のとおりです。

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のリポジトリ をご覧ください。必要なものが見つかるはずです。 SlideInItemAnimatorやSlideScaleItemAnimatorなど、RecyclerView用の単純なItemAnimatorを提供しています。

296
MathieuMaree

以下のコードに示すように、最初に表示されるときに、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);
}

setFadeAnimation()を次のsetScaleAnimation()に置き換えて、項目をある点から拡大縮小して外観をアニメートすることもできます。

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ミリ秒だけアニメーションを許可する)。

54
pbm

pbm's answer からアニメーションを作成し、アニメーションを1回だけ実行するように少し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);            
}
22

このようにRecyclerViewAndroid: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

12
Pavel Biryukov

始めるのに良い場所はこれです: https://github.com/wasabeef/recyclerview-animators/blob/master/animators/src/main/Java/jp/wasabeef/recyclerview/adapters/AnimationAdapter.Java

あなたも完全なライブラリを必要としません、そのクラスは十分です。それで、あなたがちょうどこのようなアニメーターを与えるあなたの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);
}

スクロール時に項目が下から表示され、高速スクロールの問題も回避できます。

8

アダプタでバインドされているときにリサイクルビュー内の項目をアニメートすると、リサイクルビュー内の項目が異なる速度でアニメートされる可能性があるため、最善の方法とは言えません。私の場合は、recyclerviewの最後にあるアイテムがより速くその位置にアニメートしてから、一番上にあるものがさらに移動する必要があるため、ぼんやりと見えます。

各アイテムをリサイクルビューにアニメートするために使用した元のコードは、次の場所にあります。

http://frogermcs.github.io/Instagram-with-Material-Design-concept-is-getting-real/ /

しかし、リンクが切れた場合に備えて、コードをコピーして貼り付けます。

ステップ1: アニメーションが1回だけ実行されるように、onCreateメソッド内でこれを設定します。

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

ステップ2: アニメーションを開始したい場所にこのコードを追加する必要があります。

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

推奨される代替案:

リサイクルビュー内のアイテムではなく、リサイクルビュー全体をアニメートしたいと思います。

ステップ1と2は変わりません。

STEP 3では、あなたのAPI呼び出しがあなたのデータを返すとすぐに、私はアニメーションを開始するでしょう。

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

これはあなたの全体のリサイクルビューをアニメートしてスクリーンの下から飛ぶようにします。

3
Simon

このメソッドを recyclerview Adapterに作成します。

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

そして最後に onBindViewHolder に次のコード行を追加します。

setZoomInAnimation(holder.itemView);

2

この行をRecyclerView.xmlに追加してください。

Android:animateLayoutChanges="true"
0
Avinash Verma

下のようにアダプタを拡張するだけです

public class RankingAdapter extends AnimatedRecyclerView<RankingAdapter.ViewHolder> 

そしてonBindViewHolderにsuperメソッドを追加してください

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

}
0
EliaszKubala

コーディングなし。

Gist Linkにアクセス

  <?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%" />
<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"
    />

以下のようなレイアウトやrecylcerviewで使用します。

<Android.support.v7.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" />
0
Na Ran