出現時にRecyclerViewアイテムをアニメートするにはどうすればよいですか?
デフォルトのアイテムアニメーターは、リサイクラーデータの設定後にデータが追加または削除されたときにのみアニメートします。私は新しいアプリケーションを開発しているので、どこから始めればいいのかわかりません。
どのようにこれを達成するためのアイデアはありますか?
編集:
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を提供しています。
以下のコードに示すように、最初に表示されるときに、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ミリ秒だけアニメーションを許可する)。
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);
}
このように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
始めるのに良い場所はこれです: 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);
}
スクロール時に項目が下から表示され、高速スクロールの問題も回避できます。
アダプタでバインドされているときにリサイクルビュー内の項目をアニメートすると、リサイクルビュー内の項目が異なる速度でアニメートされる可能性があるため、最善の方法とは言えません。私の場合は、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();
}
これはあなたの全体のリサイクルビューをアニメートしてスクリーンの下から飛ぶようにします。
このメソッドを recyclerview Adapterに作成します。
private void setZoomInAnimation(View view) {
Animation zoomIn = AnimationUtils.loadAnimation(context, R.anim.zoomin);// animation file
view.startAnimation(zoomIn);
}
そして最後に onBindViewHolder に次のコード行を追加します。
setZoomInAnimation(holder.itemView);
この行をRecyclerView.xmlに追加してください。
Android:animateLayoutChanges="true"
下のようにアダプタを拡張するだけです
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;
}
}
}
コーディングなし。
<?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" />