自定義RecyclerView.ItemAnimator其實(shí)很簡(jiǎn)單(上)

RecyclerView是5.0之后新添加的控件,用于在部分方面取代ListViewGridView。RecyclerView耦合性非常低,它不關(guān)心視圖相關(guān)問題。ItemDivide、LayoutManager、點(diǎn)擊事件、動(dòng)畫等都是可以動(dòng)態(tài)添加,我這次主要來說是RecyclerView.ItemAnimator的分析和自定義。RecyclerView.ItemAnimator主要用于RecyclerViewItem添加、移除、更新時(shí)的動(dòng)畫。

那我們要如何自定義呢?現(xiàn)在我們開始分析。

我們平時(shí)在使用RecyclerView的時(shí)候,沒有設(shè)置RecyclerView.ItemAnimator時(shí),我們發(fā)現(xiàn)RecyclerView在進(jìn)行Item的操作時(shí),也會(huì)存在動(dòng)畫,如下所示:

默認(rèn)ItemAnimator.gif

從下圖可以看出,系統(tǒng)默認(rèn)為我們?cè)O(shè)置了DefaultItemAnimator(410行),我們調(diào)用setItemAnimator()時(shí),改變的也是mItemAnimator的值,所以我們平時(shí)沒有設(shè)置ItemAnimator時(shí),系統(tǒng)就會(huì)執(zhí)行DefaultItemAnimator的動(dòng)畫效果。

DefaultItemAnimator.png
setItemAnimator.png

所以我們要自定義RecyclerView.ItemAnimator,就可以從DefaultItemAnimator入手了,下面我們來看DefaultItemAnimator的源碼,一點(diǎn)開這源碼的小伙伴可能就要開罵了,說好的很簡(jiǎn)單呢?600多行代碼你和我說簡(jiǎn)單,走,馬上走。但是別急,客官你聽我分析下再?zèng)Q定走不走。

DafaultItemAnimator繼承的是抽象類SimpleItemAnimator,SimpleItemAnimator主要對(duì)動(dòng)畫內(nèi)部實(shí)現(xiàn)進(jìn)行封裝,通過抽象讓我們更只關(guān)注于更具體的操作,我們定義一個(gè)BaseItemAnimator繼承SimpleItemAnimator

/**
 * Created by ivy on 2017/3/21.
 * Description:
 */

public class BaseItemAnimator extends SimpleItemAnimator {
    //Item移除回調(diào)
    @Override
    public boolean animateRemove(RecyclerView.ViewHolder holder) {
        return false;
    }

    //Item添加回調(diào)
    @Override
    public boolean animateAdd(RecyclerView.ViewHolder holder) {
        return false;
    }


    //用于控制添加,移動(dòng)更新時(shí),其它Item的動(dòng)畫執(zhí)行
    @Override
    public boolean animateMove(RecyclerView.ViewHolder holder, int fromX, int fromY, int toX, int toY) {
        return false;
    }

    //Item更新回調(diào)
    @Override
    public boolean animateChange(RecyclerView.ViewHolder oldHolder, RecyclerView.ViewHolder newHolder, int fromLeft, int fromTop, int toLeft, int toTop) {
        return false;
    }

    //真正控制執(zhí)行動(dòng)畫的地方
    @Override
    public void runPendingAnimations() {

    }

    //停止某個(gè)Item的動(dòng)畫
    @Override
    public void endAnimation(RecyclerView.ViewHolder item) {

    }

    //停止所有動(dòng)畫
    @Override
    public void endAnimations() {

    }

    @Override
    public boolean isRunning() {
        return false;
    }
}

通過代碼我們可以很清楚的知道我們要對(duì)哪些情況進(jìn)行處理,比較難理解的可能是animateMove(),這個(gè)方法的作用是在執(zhí)行某個(gè)Item的動(dòng)畫時(shí)(update item時(shí)是同一個(gè)ViewHolder也會(huì)調(diào)用該方法),其它Item的行為,可以觀看上面的Gif,簡(jiǎn)單來說,比如我們要添加一個(gè)Item的位置為1,那么后面的Item要往下移,讓出一個(gè)空位。

那我們現(xiàn)在就對(duì)DafaultItemAnimator按照上面的抽象方法一個(gè)個(gè)的分析 。#####

首先來看animateRemove()方法,內(nèi)容很簡(jiǎn)單就只有2句代碼,一句是清除和刪除要被移除Item的所有動(dòng)畫的相關(guān)代碼。第二句是往一個(gè)List中添加了當(dāng)前的ViewHolder,這個(gè)mPendingRemovals是什么呢?我們可以看到,類的開始處定義了一系列的List,看名字其實(shí)我們也可以猜出他們大概是干什么的,分別是待處理動(dòng)畫、等待運(yùn)行動(dòng)畫相關(guān)數(shù)據(jù),正在運(yùn)行動(dòng)畫的ViewHolder列表。

Paste_Image.png
Paste_Image.png

然后我們來看animateAdd()方法,和animateRemove差不多,就多了一句ViewCompat.setAlpha(holder.itemView, 0)代碼。我們觀看上面的系統(tǒng)默認(rèn)添加動(dòng)畫可以發(fā)現(xiàn),動(dòng)畫的透明度從0到1出現(xiàn)的,那這句話的作用就很明顯了,就是初始化Item的初始動(dòng)畫狀態(tài)

Paste_Image.png

現(xiàn)在輪到animateMove(final ViewHolder holder, int fromX, int fromY, int toX, int toY)方法了,這個(gè)方法有5個(gè)參數(shù),分別是要移動(dòng)的ViewHolder、起始x,y值、目標(biāo)x,y值。里面執(zhí)行的操作也很簡(jiǎn)單,就是把(添加刪除更新Item后)目標(biāo)位置和未執(zhí)行操作的當(dāng)前位置的差值計(jì)算出來,然后把Item位移到未操作前的現(xiàn)位置

Paste_Image.png

animateChange()方法和animatoMove()方法類似,只是多了一個(gè)判斷,如果是同一個(gè)ViewHolder則直接調(diào)用animatoMove(),否則在內(nèi)部多記錄了一個(gè)alpha的值

Paste_Image.png

endAnimation(ViewHolder item)方法就是取消指定item的屬性動(dòng)畫,然后把上面提到的List(待處理動(dòng)畫、等待運(yùn)行動(dòng)畫相關(guān)數(shù)據(jù),正在運(yùn)行動(dòng)畫的ViewHolder列表)里面的ViewHolder的都移除掉。

endAnimations()方法和endAnimation(ViewHolder item)方法類似,就是循環(huán)把List里面的ViewHolder都移除掉,然后把調(diào)用cancelAll()方法把所有正在執(zhí)行的屬性動(dòng)畫停止。

Paste_Image.png

isRunning()方法就很簡(jiǎn)單了,沒有執(zhí)行過多操作,就是判斷List是否為空,就知道是否有動(dòng)畫需要執(zhí)行或者正在執(zhí)行

Paste_Image.png

最后,我們來看runPendingAnimations(),這個(gè)是真正執(zhí)行動(dòng)畫的地方。首先判斷List(Pending)中是否存在待處理動(dòng)畫,如果不存在的話就退出,如果存在就開始依次執(zhí)行動(dòng)畫。

Paste_Image.png

首先判斷是否存在待移除的動(dòng)畫,如果存在,就調(diào)用animateRemoveImpl()方法執(zhí)行屬性刪除動(dòng)畫,并在動(dòng)畫開始和結(jié)束的時(shí)候?qū)?code>mRemoveAnimations進(jìn)行操作,然后清空mRemoveAnimations中的待處理移除動(dòng)畫。

Paste_Image.png

Paste_Image.png

move動(dòng)畫和change動(dòng)畫類似,相對(duì)于remove動(dòng)畫而言,他就是多了一個(gè)判斷(151),判斷是否需要?jiǎng)h除動(dòng)畫的,如果需要,等remove動(dòng)畫執(zhí)行完畢后再執(zhí)行move或者chanage動(dòng)畫,否則,直接執(zhí)行動(dòng)畫。

Paste_Image.png

add動(dòng)畫和move動(dòng)畫類似,只是判斷是否需要執(zhí)行remove、movechange動(dòng)畫,如果需要的話,等remove動(dòng)畫和move或者change的動(dòng)畫的最執(zhí)行時(shí)長(zhǎng)之和執(zhí)行完畢后再執(zhí)行,否則立即執(zhí)行動(dòng)畫。

Paste_Image.png

到這里,我們就對(duì)默認(rèn)的DefaultItemAnimator動(dòng)畫就分析完畢了,我們也了解內(nèi)部是怎么實(shí)現(xiàn)的。對(duì)如何實(shí)現(xiàn)自己的RecyclerView.ItemAnimator也有了一個(gè)大概的思路。

下一步,就讓我們來定義自己的RecyclerView.ItemAnimator。#####
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 這篇文章分三個(gè)部分,簡(jiǎn)單跟大家講一下 RecyclerView 的常用方法與奇葩用法;工作原理與ListView比...
    LucasAdam閱讀 4,687評(píng)論 0 27
  • 簡(jiǎn)介: 提供一個(gè)讓有限的窗口變成一個(gè)大數(shù)據(jù)集的靈活視圖。 術(shù)語表: Adapter:RecyclerView的子類...
    酷泡泡閱讀 5,358評(píng)論 0 16
  • RecyclerView包含以下幾個(gè)重要的組件:1.LayoutManager: 測(cè)量和布局子View2.Recy...
    烏龜愛吃肉閱讀 3,639評(píng)論 4 7
  • “點(diǎn)贊”這個(gè)詞對(duì)于生活在互聯(lián)網(wǎng)時(shí)代的人來說是再熟悉不過的了。君不見那微信朋友圈上發(fā)出來的任何一條信息都會(huì)獲得若...
    石媽媽閱讀 381評(píng)論 0 1
  • 2016年11月21日 周一 下午老叔來電話說:房子已經(jīng)租完,買煤盤電炕,窗戶蒙上塑料布等等準(zhǔn)備工作在老親少友的幫...
    魅力春天閱讀 234評(píng)論 0 1

友情鏈接更多精彩內(nèi)容