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の実装原則を使用して、現在のアニメーションの妥当なライフサイクル管理を実現する方法を検討します。
アイプリンシパル
- 個人ウェブサイト、





