blog

これはおそらく、今まで見た中で最も単純なRecyclerView Itemのロードアニメーションだ!

もちろん欠点もあります。これは特定の使用シナリオのトレードオフ次第で、もしかしたらサポートできるかもしれませんが、今のところどうすればいいかは考えていません。 今のところ正しいのはこの2つです。 ロー...

Dec 14, 2020 · 6 min. read
シェア

RecyclerView Itemアニメーションを実装するには?

この問題は、多くの人々が言うに違いない、私はItemAnimatorを使用して、ああを達成するために、これはRecyclerViewのインターフェイスの公式の定義であり、具体的には、アイテムのアニメーションを拡張するために、なぜ私はそれを達成するために別の方法を模索する必要がありますか?最近、問題に反映されるため、実際には、多くの人が思考のこの法則を持っている、つまり、公式は、本当に良いことでなければなりませんか?ここで、私は別の角度から公式ItemAnimatorが本当に良くないことを説明するために来ます。

ItemAnimator 放棄の理由

グラウンド1

  • 最初のイメージは、最も素晴らしく、星のようなwasabeef/recyclerview-animatorsです、基本クラスは713行のコードを持っています、あなたはこのクラスがパッケージ化されている大きさを知っていますか?20キロバイト以上あります。
  • もう1つは公式のデフォルト・アニメーションで、これも700行近くあります。

理由: コードの肥大化

理由2

ItemAnimatorインターフェイスを使いたいし、公式のDefaultItemAnimatorがあるのだから、DefaultItemAnimatorを継承して、代わりにSimpleItemAnimatorを実装して、Itemのアニメーションを実行できるように700行のコードを書くことはできないのでしょうか?とにかく、SimpleItemAnimatorを継承した後は、DefaultItemAnimatorとほとんど同じ実装になることを知ると、冗長なコードを見たくない、ちょっときれいフェチなのかもしれない、と思ってお断りしました。

その理由は、再利用率があまりにも低く、当局がまったく真剣に取り組んでいないように感じられるからです

理由3

notifyDataSetChangedはItemAnimatorのアニメーションをサポートしていません。この設計が本当に良いか悪いかは議論しませんが、少なくとも私がItemAnimatorを選択しないもう一つの理由です。

待って、他に言うことない?こういう欠点があるにもかかわらず、使わなければならない時が必ずあると思いませんか?

layoutAnimation 放棄の理由

ItemAnimatorを使用している人のほとんどは、直接例を見て、それを放棄する理由を言います!

step1

<set xmlns:android="http://..///id"
 android:duration="@integer/anim_duration_medium">
 <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>

step2

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

step3

int resId = R.anim.layout_animation_fall_down;
LayoutAnimationController animation = AnimationUtils.loadLayoutAnimation(ctx, resId);
recyclerview.setLayoutAnimation(animation);

デモを走らせたときはうまくいっているように見えたのですが、最終的に何かがおかしいことに気づいて、使うのをやめました。

グラウンド1

アニメーションがロードされるのは最初の画面だけ?変更できるかどうかは調べていませんが、このようなエフェクトは我慢できないのですが、laに進むと、下の表示されていないItemのアニメーションが消えているのはなぜでしょう?それが断念した理由です。

理由2

GridLayoutMangerを使う場合は、xmlファイルを追加するだけですが、layhoutAnimationのセットを定義する必要がありますが、これから紹介するソリューションの実装には及ばないので、断念することにしました。

最もシンプルなアニメーションプログラム

このプログラムの強み

  • コードは非常にクリーン
  • アニメーションはよりカスタマイズ可能で、すべてのアイテムに簡単に、さまざまな方法でアニメーションをロードできます。
  • プリロード・アニメーション可能、アップデート・アニメーション可能
  • ローディングアニメーションを簡単に実装できます。
  • キャッシュはより軽量で、メモリのオーバーヘッドを削減します。

デメリット:確かにデメリットはありますが、これは特定の使用シナリオのトレードオフ次第です。

  • アニメーションの削除なし
  • アニメーションなし

今のところ、右の2つだけです。

実装原則

xmlで設定したビューのアニメーションを読み込むのはとても簡単です。

コード実装

step1

下から上に移動するアニメーション

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://..///id"
 android:duration="@integer/anim_duration_long">
 <translate
 android:interpolator="@android:anim/accelerate_decelerate_interpolator"
 android:fromYDelta="50%p"
 android:toYDelta="0"
 />
 <alpha
 android:fromAlpha="0"
 android:toAlpha="1"
 android:interpolator="@android:anim/accelerate_decelerate_interpolator"
 />
</set>

step2

//次から次へと遅延アニメーションをゼロからカウントする。
private var delayPosition = 0
//アニメーションをキャッシュする, loadAnimationの繰り返しを避ける, オーバーヘッドを減らす
private val animationArray = SparseArray<Animation>()
//xmlアニメーションを読み込み、キャッシュに入れる。
private fun loadAnimation(context: Context, @AnimRes itemAnimationRes: Int, key: Int): Animation {
 return animationArray[key] ?: AnimationUtils.loadAnimation(context, itemAnimationRes).apply {
 animationArray.append(key, this)
 }
}
//キャッシュ
fun RecyclerView.onDestroy(){
 animationArray.clear()
}
//アニメーションを実装する
fun RecyclerView.ViewHolder.animationWithDelayOffset(
 isEnableAnimation: Boolean,
 @AnimRes itemAnimationRes: Int,
 delayOffset: Int
) {
 if (isEnableAnimation) {
 	//アニメーションをクリーンアップする
 itemView.clearAnimation()
 //現在のアイテム位置
 val currentPosition = ++delayPosition
 //次のアイテムの遅延時間を計算する。
 val delay = currentPosition * delayOffset / 2
 itemView.animation =
 loadAnimation(itemView.context, itemAnimationRes, currentPosition).apply {
 	//実行開始をどれくらい遅らせるか
 startOffset = delay.toLong()
 //ロード後のカウントをゼロにする
 setAnimationListener(object : Animation.AnimationListener {
 override fun onAnimationRepeat(p0: Animation?) {
 }
 override fun onAnimationEnd(p0: Animation?) {
 delayPosition = 0
 }
 override fun onAnimationStart(p0: Animation?) {
 }
 })
 //Startは、アニメーションがすでに一度実行されている場合にのみ呼び出される。.loadAnimation読み込まれると自動的に一度だけ実行される。
 if (this.hasEnded()) {
 this.start()
 }
 }
 }
}
//これは、DefaultViewHolderは、私はViewModelは、ああ実装の初期化後の最初の時間だけを達成することができるように、最初の時間isFirstInitを取得することができる!
fun DefaultViewHolder.firstAnimation(
 @AnimRes itemAnimationRes: Int = R.anim.item_animation_from_right,
 delayOffset: Int = 200
) = animationWithDelayOffset(
 getViewModel<ViewModelType>()?.isFirstInit ?: false,
 itemAnimationRes,
 delayOffset
)
//ViewModelを取得する最初のisFirstInitなので、ああ、2番目のロード実行だけを達成することができる!
fun DefaultViewHolder.updateAnimation(
 @AnimRes itemAnimationRes: Int = R.anim.item_animation_scale
) = animation(!(getViewModel<ViewModelType>()?.isFirstInit ?: false), itemAnimationRes)

step3

アプリケーション、1行のコード

更新時のアニメーションの設定(1行

このシンプルさ、あなたも体験してみたいと思いませんか?

デモアドレス、体験歓迎

次の課題は?

これは本当にItemAnimatorより優れているのでしょうか?もちろん、いつブレークするか、いつリロードするか、いつキャッシュをクリアするのが理にかなっているかなど、いくつかの問題はあります。この問題を解決するには、もう少し包括的な練習が必要です。また、ItemAnimatorの実装原則を使用して、現在のアニメーションの妥当なライフサイクル管理を実現する方法を検討します。

アイプリンシパル

  • 個人ウェブサイト、
Read next

あなたは本当にJavaの継承関係に詳しいのだろうか?そして、親クラスのprivate修飾子が継承できることを知っているだろうか?

javaの継承についてですが、私がjavaを習い始めた頃は、親クラスのprivate修飾子は子クラスには継承できないと思っていました。その後、勉強が深まるにつれ、もっと見る、いくつかの記事ブログ別の視点を参照してください:実際には、親クラスのものは、コンストラクタのメソッドに加えて、他のすべてのものは、privateを含めて継承することができます。しかし、物事のプライベートの変更のため、このクラスでのみ表示することができます。...

Dec 14, 2020 · 6 min read

Nettyを知る

Dec 14, 2020 · 6 min read

プロミスのJS実装

Dec 13, 2020 · 5 min read