recyclerview item動畫_這可能是你見過的迄今為止最簡單的RecyclerView Item加載動畫...

如何實現RecyclerView Item動畫?

這個問題想必有很多人都會講,我可以用ItemAnimator實現啊,這是RecyclerView官方定義的接口,專門擴展Item動畫的,那我為什么要尋求另外一種方法實現呢?因為最近反思了一個問題,其實很多人都有這個思維定律,那就是官方的一定是好的,真的是這樣嗎?下面我來從另一個角度說明官方的ItemAnimator是真的不好用

ItemAnimator 棄用理由

理由一

7ff84ba02899720f58cebbe945033a89.png
77c1acbad53cca77673b8a61e46ee002.png
  • 第一張圖是最牛逼的星星最多的wasabeef/recyclerview-animators,基類有713行代碼,你知道這個類打包出來多大嗎?有20多kb,相當恐怖的好嗎?
  • 第二個是官方提供的默認動畫,也是將近700行

理由是:代碼過于臃腫

理由二

既然我想用ItemAnimator接口,且官方有一個DefaultItemAnimator,為什么我不能擴展DefaultItemAnimator,而是要實現SimpleItemAnimator,寫個700行代碼才能夠捋明白一個Item的動畫?總之,當我知道繼承SimpleItemAnimator后,實現的和DefaultItemAnimator幾乎一樣的時候,我內心是拒絕的,我不想看到這些冗余的代碼,也許是我有那么一點點潔癖

理由是:復用率太低,感覺官方根本沒當回事(也許是我學習沒到位,沒有看到它好的地方)

理由三

notifyDataSetChanged不支持ItemAnimator動畫,我不討論這么設計是真的好和壞,但起碼它是我不選擇ItemAnimator的另一個理由

等等吧,不知道還能吐槽什么了?雖然有這些缺點,可我們總會遇到不得不用的時候,你說呢?

layoutAnimation 棄用理由

這個用的比較少吧,大部分都是在用ItemAnimator,我們直接看個例子,然后再說為什么要棄用它

step1

     android:duration="@integer/anim_duration_medium">

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

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

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


step2

<?xml version="1.0" encoding="utf-8"?>
xmlns:android="http://schemas.android.com/apk/res/android"
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);

很簡單對吧,當我運行demo的時候,似乎看起來效果很好哦,可最后我才發現一些問題,我決定不使用它了

理由一

動畫只加載第一屏?這個能不能改觀我沒有深入研究哦,可這樣一個效果我也無法忍受,但我上啦的時候,為什么下面未顯示的Item動畫就沒了呢?這就是我棄用的理由

理由二

當我用GridLayoutManger 的時候,我還要在定義一套 layhoutAnimation,雖然只是增加了一個xml文件,可這比起我接下來介紹的實現方案,那就差了一個檔次,所以我選擇棄用

最簡單的Animation動畫方案

這個方案的優勢:

  • 代碼超級簡潔
  • 動畫的定制度更高,沒一個Item都可以輕松的且變著花樣的加載動畫
  • 可實現預加載動畫,可實現更新的動畫
  • 輕松實現一個接一個的加載動畫
  • 緩存更加輕量級,減少內存開銷

缺點:當然也有缺點,這個看具體使用場景的取舍,也許是可以支持的,但目前我還沒有想到如何做到。

  • 沒有刪除動畫
  • 沒有移動動畫

對的目前就這倆。

實現原理

很簡單,就是給View加載一個Animation,通過xml配置

實現效果

701e82c6273195df461cc1d82218e8e6.gif

代碼

step1

從下往上移動的動畫

<?xml version="1.0" encoding="utf-8"?>
android:duration="@integer/anim_duration_long">
android:interpolator="@android:anim/accelerate_decelerate_interpolator"
android:fromYDelta="50%p"
android:toYDelta="0"
/>

android:fromAlpha="0"
android:toAlpha="1"
android:interpolator="@android:anim/accelerate_decelerate_interpolator"
/>

step2

//從零開始計數,用來實現一個接一個的延遲動畫(簡單點就是:在一個加載一半時,下一個才執行)
private var delayPosition = 0
//緩存Animation,避免重復loadAnimation,減少開銷
private val animationArray = SparseArray()
//加載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()
//當前item positon
val currentPosition = ++delayPosition
//計算下一個Item需要delay的時間
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,因為第一次用AnimationUtils.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()?.isFirstInit ?: false,
itemAnimationRes,
delayOffset
)
//拿到ViewModel是否是第一次isFirstInit,這樣就可以實現只有第二次加載執行哦
fun DefaultViewHolder.updateAnimation(
@AnimRes itemAnimationRes: Int = R.anim.item_animation_scale
) = animation(!(getViewModel()?.isFirstInit ?: false), itemAnimationRes)

代碼里有個細節處理《加載完成后將計數制成零》,這里是因為,你第一次進頁面的時候,所有的Item的都按照順序執行完畢后,由于delay數很大,導致你滑動的時候,會出現很久才加載進來的動畫哦,這里我是想用handler的postdelay實現,這樣就可以做到只要有接著的動畫執行,就不會被重制成0,保證下次動畫的執行一定是在上一個Item的后面,這樣確實是一個問題,也許在我驗證夠多的場景后就切過去了,嘿嘿。但目前來看,這個效果實現的很滿意,慢慢重構和完善。當然我的這種實現方式,確實是比較簡單而且效果還不錯,既有LayoutAnimation的影子,又有ItemAnimator的功能,豈不是很不錯。

step3

應用,一行代碼搞定

d8f75e9c37f65f75abc6140f7252b92f.png

配置更新時候的動畫,一行搞定f88d7078fe70e14245fe8b7707a37ffa.png

感覺到簡單了吧,這么順滑的動畫實現,你不想體驗下嗎?

Demo地址,歡迎體驗

https://github.com/ibaozi-cn/RecyclerViewAdapter

接下來會解決什么問題?

這么用難道確實比ItemAnimator好嗎?當然會有一些問題吧,比如什么時候需要中斷,什么時候需要重新加載,甚至到底什么時候清理掉緩存更合理呢?之后還需要一些更全面的實戰來解決這問題,也會借助ItemAnimator的實現原則來考慮當前動畫如何做到合理的生命周期管理。

作者

i校長

  • 簡書 https://www.jianshu.com/u/77699cd41b28
  • 掘金 https://juejin.im/user/131597127135687
  • 個人網站 http://jetpack.net.cn ?、 http://ibaozi.cn

30655d213ee4f6e0727d8e67cec8a323.png

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/538266.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/538266.shtml
英文地址,請注明出處:http://en.pswp.cn/news/538266.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

群暉編譯LCD4Linux,LCD4LINUX配置文件一些參數使用解釋。

#LCD顯示配置Display dpf {Driver DPF #LCD驅動類型Port usb0 #連接端口Font 6x8 #字體大小Foreground ffffff #字體…

VBoxManage: error: Nonexistent host networking interface, name 'vboxnet0' (VERR_INTERNAL_ERROR)

錯誤&#xff1a; VBoxManage: error: Nonexistent host networking interface, name vboxnet0 (VERR_INTERNAL_ERROR) 原因&#xff1a; 原來配置的網卡發生了變更&#xff0c;找不到了&#xff0c;啟動失敗。 解決方法&#xff1a; 第一步&#xff0c;命令&#xff1a; V…

捷信達溫泉管理軟件員工卡SQL查詢

捷信達溫泉管理軟件員工卡SQL查詢 select * from snkey where v_name2 like %員工% 網名&#xff1a;浩秦; 郵箱&#xff1a;root#landv.pw; 只要我能控制一個國家的貨幣發行&#xff0c;我不在乎誰制定法律。金錢一旦作響&#xff0c;壞話隨之戛然而止。

Linux 軟件安裝到 /usr,/usr/local/ 還是 /opt 目錄?

Linux 的軟件安裝目錄是也是有講究的&#xff0c;理解這一點&#xff0c;在對系統管理是有益的 /usr&#xff1a;系統級的目錄&#xff0c;可以理解為C:/Windows/&#xff0c;/usr/lib理解為C:/Windows/System32。 /usr/local&#xff1a;用戶級的程序目錄&#xff0c;可以理解…

winpe裝雙系統linux_使用syslinux在u盤安裝pubbylinux和winpe雙系統

使用syslinux在u盤安裝pubbylinux和winpe雙系統1,在u盤里安裝winpe,請參見"比較簡單的制作U盤winpe啟動盤方法"比較簡單的制作U盤winpe啟動盤方法 收藏1,下載一個深度winpev3.iso2,用winrar或ultraISO解壓深度winpev3.iso3,進入解壓出來的文件夾下&#xff0c;找到se…

esp32 嵌入式linux,初體驗樂鑫 ESP32 AT 指令-嵌入式系統-與非網

樂鑫 AT 固件初體驗初步體驗 AT 指令下 TCP 數傳&#xff0c;為了驗證 AT 命令解析器。前往樂鑫官網 下載最新版本 AT 固件和 AT 指令集手冊。硬件準備本文使用樂鑫的 ESP-WROOM-32(ESP-WROOM-32 是 ESP32-WROOM-32 的曾用名)模塊&#xff0c;4MB Flash&#xff0c;無 PSRAM。E…

主機ping不通Virtualbox里的虛擬機

在redhat上安裝了VirtualBox&#xff0c;虛擬了三臺Linux機器。 宿主機網卡更換過了。三臺虛擬機無法啟動了&#xff0c;搭建虛擬機的運維離職了。 VirtualBox的圖形界面壞了&#xff0c;啟動不了。只能用命令行&#xff0c;今天時間就花在命令行上了。 第一個問題是&#xf…

python后端開發靠譜嗎_【后端開發】python有這么強大嗎

因為Python是一種代表簡單主義思想的語言。除此之外&#xff0c;Python所擁有的標準庫更是金融、營銷類人群選擇它的理由。Python 易于學習可靠且高效(推薦學習&#xff1a;Python視頻教程)好吧&#xff0c;相較于其它許多你可以拿來用的編程語言而言&#xff0c;它“更容易一些…

linux 卸載 openldap,Linux下安裝openldap

Ubuntu apt-getinstall安裝參考&#xff1a;http://dongwang.wordpress.com/category/uncategorized/普通linux安裝,以XXX用戶身份安裝&#xff1a;1、安裝BerkeleyDB 4.7.25&#xff1a;伯克利大學嵌入式數據庫解決方案,openldap拿它作為存儲方案。http://download.oracle.com…

Git之原有基礎開發新功能

場景描述 當一個項目已經上線&#xff0c;同時又在原有基礎上新增功能模塊&#xff0c;于是乎就要在原有代碼的基礎上進行開發&#xff0c;在新增模塊功能的開發的過程中&#xff0c;項目發現了一個緊急Bug&#xff0c;需要修復。操作流程如下&#xff1a; -------------------…

pantum打印機驅動安裝m6506_奔圖Pantum M6506NW 驅動

這是奔圖Pantum M6506NW 驅動&#xff0c;是M6506NW奔圖打印機驅動&#xff0c;此設備內置WIFI熱點&#xff0c;安裝驅動可以幫助用戶解決打印機連接和工作中出現的問題&#xff0c;非常方便&#xff0c;需要的朋友快來本站下載吧&#xff01;驅動介紹奔圖M6506NW一體機驅動專為…

linux kvm查看線程狀態,kvm線程-005-線程狀態-THREAD_JUST_BORN

在kvm內部定義了線程狀態,如下:enum {THREAD_JUST_BORN 1, /* 還沒有啟動*/THREAD_ACTIVE 2, /* 當前正在運行,或者在等待運行的隊列中*/THREAD_SUSPENDED 4, /* 等待monitor或者alarm */THREAD_DEAD 8, /* 線程退出 */THREAD_MONITOR_WAIT 16, // 等待鎖THREAD_CONVAR_WA…

詳解VirtualBox虛擬機網絡環境解析和搭建-NAT、橋接、Host-Only、Internal、端口映射

原文鏈接&#xff1a;http://www.jb51.net/article/98575.htm -------------------------------------------------- 本文以VirtualBox為例 如果出現主機無法ping通虛擬機的情況&#xff0c;請首先確認虛擬機防火墻已關閉。 一、NAT模式 特點&#xff1a; 1、如果主機可以上網…

os.popen read()報編碼錯誤_數據科學家易犯的十大編碼錯誤,你中招了嗎?

選自 Medium作者&#xff1a;Norm Niemer機器之心編譯參與&#xff1a;李詩萌、王淑婷數據科學家比軟件工程師擅長統計&#xff0c;又比統計學家擅長軟件工程。聽起來牛逼轟轟&#xff0c;事實卻是&#xff0c;許多數據科學家有統計學背景&#xff0c;卻沒有什么軟件工程方面的…

linux怎么添加工作組,linux 用戶與工作組

在linux 里面&#xff0c;用戶的編號UID &#xff0c;也就是用戶的ID號。工作組的編號為GID 也就是工作組的ID 號 。1、用戶的分類超級用戶&#xff1a;root用戶&#xff0c;系統安裝過程中自動創建&#xff0c;UID 為0。普通用戶&#xff1a;操作權限受到限制的用戶id在 500-6…

MySQL5.7.12新密碼登錄方式及密碼策略

原文鏈接&#xff1a;http://www.cnblogs.com/jonsea/p/5510219.html --------------------------------------------------------------------------- 松門一枝花補充 最簡單的方法&#xff1a; 1、配置文件中把密碼策略關了。本文中間部分有介紹。 2、重啟服務 3、用my…

聚類分析在用戶行為中的實例_聚類分析案例之市場細分

聚類是將數據分類到不同的類或者簇這樣的一個過程&#xff0c;所以同一個簇中的對象有很大的相似性&#xff0c;而不同簇間的對象有很大的相異性。從統計學的觀點看&#xff0c;聚類分析是通過數據建模簡化數據的一種方法。傳統的統計聚類分析方法包括系統聚類法、分解法、加入…

linux 編譯system.img,android生成sysytem.img的命令過程

Fromhttp://xianghuaclm.blog.163.com/blog/static/6668783201110221486240/使用#file system.img輸出&#xff1a;system.img: Linux rev 0.0 ext2 filesystem data,UUID4eb0489c-647d-49d8-9111-94657b5fd342, volume name"system"。然而本人使用命令#mkyaffs2imag…

Hive的hiveserver2后臺開啟和關閉

前提&#xff1a;hive/bin配置了環境變量。如果沒有配置&#xff0c;cd到 hive目錄下的bin里&#xff0c;再執行。 開啟命令&#xff1a; nohup hive --service hiveserver2 & 產生的日志&#xff1a; 默認在&#xff1a; 用戶文件夾里 [rootmaster ~]# ll total 80 …

記一次,jvm 內存溢出

1、什么是內存泄漏內存泄漏是指&#xff0c;有未被釋放的java對象&#xff0c;一直停留在內存中。GCRoot 無法追蹤到此對象&#xff0c;導致此對象無法被回收。 2、什么是內存溢出內存溢出是指&#xff0c;java程序創建對象需要內存&#xff0c;但是卻沒有內存可用了&#xff0…