Android動畫了解—RecyclerView Animator

Recyclerview animation

什麼時候開始的 RecyclerView animation,在我們UI 2.0~3.0的時候,很多地方都需要這種 RecyclerView 界面 初始化添加移除更新 數據的 動畫效果樣式.

看幾個RecycelrView Adapter 初始化的小DEMO
在這裏插入圖片描述
在這裏插入圖片描述
除了這種方式進行初始化,我們還可以用前面所講的過渡動畫來進行

Transition explode = new Explode();
explode.setDuration(1000);
TransitionManager.beginDelayedTransition(recyclerView, explode);
if (recyclerView.getAdapter() != null) {
	recyclerView.setAdapter(null);
} else {
	recyclerView.setAdapter(mColorsAdapter);
}

在這裏插入圖片描述

再看看 RecyclerView Item 添加,移除,更新的的小栗子
在這裏插入圖片描述

如果沒有設置 Item animation,RecyclerView 默認使用的就是 DefaultItemAnimator(繼承的 SimpleItemAnimator)

如果想實現上面的一些效果(Demo地址),我們就需要 自定義自己的 Item Animator ,只需要繼承 SimpleItemAnimator,重寫幾個關鍵的重要函數

函數名 含義
animateRemove item 移除時的動畫
animateAdd item 添加時的動畫
animateMove 移動時的動畫 列表項位置移動時調用
animateChange item 更新時的動畫
runPendingAnimations 真正控制執行動畫的地方
endAnimation 停止某個Item的動畫
endAnimations 停止所有動畫
isRunning 返回當前是否有動畫需要執行

在自定義Item Animator 中會調用到的相關函數:

函數名 含義
dispatch(Add/Remove/Move/Change)Starting 動畫開始時調用,比如Add dispatchAddStarting
dispatch(Add/Remove/Move/Change)Finished 動畫結束時調用,比如Add dispatchAddFinished
dispatchAnimationsFinished 所有動畫結束時調用

引發 Item 動畫的幾個函數

Adapter.notifyItemInserted(int position) // 觸發 Add Item Animator
Adapter.notifyItemRemoved(int position) // 觸發 Remove Item Animator
Adapter.notifyItemChanged(int position) // 觸發 Change Item Animator
Adapter.notifyItemMoved(int fromPosition, int  toPosition) // 觸發 MoveItem Animator

先來自定義的一個添加Item View的動畫效果的小DEMO

public class CumtomAnimator extends SimpleItemAnimator {
	// 保存 需要做 add 動畫效果的 itemView 的數組
	private ArrayList<RecyclerView.ViewHolder> mPendingAdditions = new ArrayList<>();
	@Override
    public boolean animateAdd(RecyclerView.ViewHolder holder) {
    	// 添加對應的數據,主要用於 runPendingAnimations 執行動畫效果
    	mPendingAdditions.add(holder);
    }
    @Override
    public void runPendingAnimations() {
    	for (RecyclerView.ViewHolder holder : mPendingAdditions) {
            ViewCompat.animate(holder.itemView)
                    .scaleX(1.0f)
                    .scaleY(1.0f)
                    .setDuration(getAddDuration())
                    .start();
        }
        // 記得要清理掉,不然其它動畫執行後,要被影響,而且也影響 isRunning 的判斷
        mPendingAdditions.clear();
	}
	@Override
    public boolean isRunning() {
        return !mPendingAdditions.isEmpty()
               || ... ...
    }
    ... ...
}

ViewCompat:android官方實現兼容的一個幫助類,具體可以查找網上相關資料 官方資料

可以試試(notifyItemInserted(position))有沒有動畫效果,肯定是沒有效果的,因爲沒有去初始化它 起始的樣子!!!
在這裏插入圖片描述

來改改代碼… …

... ...
public boolean animateAdd(RecyclerView.ViewHolder holder) {
	// 初始化動畫狀態
    // 將 ItemView 設置爲 ScaleX,ScaleY 都爲0
    // 那麼執行動畫效果的時候,就是從 中間位置 然後 放大 0.0f -> 1.0f
    View itemView = holder.itemView;
    ViewCompat.setPivotY(itemView, itemView.getMeasuredHeight() / 2);
    ViewCompat.setPivotX(itemView, itemView.getMeasuredWidth() / 2);
    ViewCompat.setScaleX(itemView, 0);
    ViewCompat.setScaleY(itemView, 0);
    // 添加對應的數據,主要用於 runPendingAnimations
    mPendingAdditions.add(holder);
}
... ...

代碼修改後,添加 ItemView 就能達到下面的效果。
在這裏插入圖片描述
你會發現,上面的 RecyclerView ItemView的添加動畫效果,還行,就是新增的時候,下面的其它的ItemView 移動的很生硬,所以這裏就引出了 animateMove 函數。

函數名 參數 參數含義
animateMove (final ViewHolder holder, int fromX, int fromY, int toX, int toY) 列表項位置移動時調用,移動的ViewHolder;fromX 起始x,y值;toX 目標x,y值
@Override
public boolean animateMove(RecyclerView.ViewHolder holder, int fromX, int fromY, int toX, int toY) {
	// 設置它的初始位置.
	final View view = holder.itemView;
	// 目標的位置 減去 起始位置(原來的位置),得到需要位移的距離
    int deltaX = toX - fromX;
    int deltaY = toY - fromY;
    // 設置後,相當於從 新的位置 回到了 原來的位置上.
    if (deltaX != 0) {
       ViewCompat.setTranslationX(view, -deltaX);
    }
    if (deltaY != 0) {
    	ViewCompat.setTranslationY(view, -deltaY);
    }
    mPendingMoves.add(new MoveInfo(holder, fromX, fromY, toX, toY));
}

@Override
public void runPendingAnimations() {
    ... ...
    // 最後從原來的位置 做動畫,回到新的位置上,就完整了移動的動畫效果.
	for (MoveInfo moveInfo : mPendingMoves) {
		ViewCompat.animate(moveInfo.holder.itemView)
                  .translationX(0)
                  .translationY(0)
                  .setDuration(getMoveDuration())
                  .start();
	}
	mPendingMoves.clear();
	... ...
}

整個添加Item View的動畫效果,就這樣完成啦!!!
在這裏插入圖片描述
當然在項目,肯定沒有那麼簡單,這裏只是簡單的舉個小栗子,給大家說明下幾個函數的重要性.

如果是項目中使用,只需要繼承這個 BaseitemAnimator,寫一些自己想要的效果就OK,不過這裏已經實現了大多數的動畫效果。
在這裏插入圖片描述 在這裏插入圖片描述
需要使用以上效果的小夥伴,自行下載,代碼庫地址
在這裏插入圖片描述

5.x 參考資料

RecyclerView animations 國外大神文章
RecyclerView anim視頻

掌握RecyclerView動畫不得不看的文章

谷歌API文檔

深入理解 RecyclerView 系列之二:ItemAnimator

自定義RecyclerView ItemAnimator 上

自定義RecyclerView ItemAnimator 下


Android動畫了解—轉場/過渡(Transition) 動畫<=上個章節 下個章節=> Android動畫了解—其它動畫

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章