自定義RecyclerView動畫——實現remove飛出效果
我們經常會遇到在一個list中刪除一條資料,這時候一般會有一個飛出的動畫效果,如下圖:
在RecyclerView中可以通過setItemAnimator函式設定一個ItemAnimator,實現item的add、remove、change等動作的動效。下面我們就通過ItemAnimator來實現上面的效果。
首先建立一個類,繼承至SimpleItemAnimator,如下:
class FlyAnimator extends SimpleItemAnimator{
@Override
public boolean animateRemove(RecyclerView.ViewHolder holder) {
return false;
}
@Override
public boolean animateAdd(RecyclerView.ViewHolder holder) {
return false;
}
@Override
public boolean animateMove(RecyclerView.ViewHolder holder, int fromX, int fromY, int toX, int toY) {
return false;
}
@Override
public boolean animateChange(RecyclerView.ViewHolder oldHolder, RecyclerView.ViewHolder newHolder, int fromLeft, int fromTop, int toLeft, int toTop) {
return false;
}
@Override
public void runPendingAnimations() {
}
@Override
public void endAnimation(RecyclerView.ViewHolder item) {
}
@Override
public void endAnimations() {
}
@Override
public boolean isRunning() {
return false;
}
}
SimpleItemAnimator是一個抽象類,需要實現幾個函式。
因為我們要實現是一個remove的動作,需要在animateRemove中處理。這裡我們參照DefaultItemAnimator的做法,首先需要兩個list,然後在animateRemove將holder新增進list中,這裡暫時不做處理,如下:
List<RecyclerView.ViewHolder> removeHolders = new ArrayList<>();
List<RecyclerView.ViewHolder> removeAnimators = new ArrayList<>();
@Override
public boolean animateRemove(RecyclerView.ViewHolder holder) {
removeHolders.add(holder);
return true;
}
至於另外一個list下面會用到。
既然我們在animateRemove函式中不做動效處理,那麼應該在哪裡處理?
答案是在runPedingAnimations中來處理,程式碼如下:
@Override
public void runPendingAnimations() {
if(!removeHolders.isEmpty()) {
for(RecyclerView.ViewHolder holder : removeHolders) {
remove(holder);
}
removeHolders.clear();
}
}
遍歷removeHolders,依次執行remove,這個函式是自定義的,用於執行動畫,程式碼如下:
private void remove(final RecyclerView.ViewHolder holder){
removeAnimators.add(holder);
TranslateAnimation animation = new TranslateAnimation(0, 1000, 0, 0);
animation.setDuration(500);
animation.setAnimationListener(new Animation.AnimationListener() {
@Override
public void onAnimationStart(Animation animation) {
dispatchRemoveStarting(holder);
}
@Override
public void onAnimationEnd(Animation animation) {
removeAnimators.remove(holder);
dispatchRemoveFinished(holder);
if(!isRunning()){
dispatchAnimationsFinished();
}
}
@Override
public void onAnimationRepeat(Animation animation) {
}
});
holder.itemView.startAnimation(animation);
}
可以看到就是對holder的itemview執行來一個移動動畫。
這裡使用removeAnimators來管理所有的remove動畫,目前是判斷所有的remove動畫是否結束,這個判斷在isRunning函式中,程式碼如下:
@Override
public boolean isRunning() {
return !(removeHolders.isEmpty() && removeAnimators.isEmpty());
}
當兩個list都為空的時候,所有動畫都完成了,回到remove程式碼中這時候執行disPatchAnimationsFinished函式。
通過上面幾步,實現了remove的動效,當我們執行的時候發現確實有了飛出的效果,但是下面的item卻瞬間上移導致重疊。效果如下:
這時因為我們目前只定義了remove的效果,實際上不僅有飛出的動作還有一個上移的動作,所以還需要定義一下move的效果,同remove一樣需要兩個list,在animateMove函式中將holder新增至list中,如下:
List<RecyclerView.ViewHolder> moveHolders = new ArrayList<>();
List<RecyclerView.ViewHolder> moveAnimators = new ArrayList<>();
@Override
public boolean animateMove(RecyclerView.ViewHolder holder, int fromX, int fromY, int toX, int toY) {
holder.itemView.setTranslationY(fromY - toY);
moveHolders.add(holder);
return true;
}
注意在remove的一瞬間,下方的item實際上就已經上移了,所以在animateMove中設定item的translationY使其保持在未上移的位置。
然後同樣在runPedingAnimations中處理,這時runPedingAnimations程式碼如下:
@Override
public void runPendingAnimations() {
if(!removeHolders.isEmpty()) {
for(RecyclerView.ViewHolder holder : removeHolders) {
remove(holder);
}
removeHolders.clear();
}
if(!moveHolders.isEmpty()){
for(RecyclerView.ViewHolder holder : moveHolders) {
move(holder);
}
moveHolders.clear();
}
}
這裡move同樣是自定義的一個函式,程式碼如下:
private void move(final MoveInfo moveInfo){
moveAnimators.add(moveInfo);
ObjectAnimator animator = ObjectAnimator.ofFloat(moveInfo.holder.itemView,
"translationY", moveInfo.holder.itemView.getTranslationY(), 0);
animator.setDuration(500);
animator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationStart(android.animation.Animator animation) {
dispatchMoveStarting(moveInfo.holder);
}
@Override
public void onAnimationEnd(android.animation.Animator animation) {
dispatchMoveFinished(moveInfo.holder);
moveAnimators.remove(moveInfo.holder);
if(!isRunning()) dispatchAnimationsFinished();
}
});
animator.start();
}
執行了一個屬性動畫,修改了item的translationY使其上移回原位置。同時注意修改isRunning函式,如下:
@Override
public boolean isRunning() {
return !(removeHolders.isEmpty() && removeAnimators.isEmpty() && moveHolders.isEmpty() && moveAnimators.isEmpty());
}
這樣就實現了一開始的飛出效果。
總結一下,其實自定義ItemAnimator比較簡單,雖然程式碼接近百行,但其實主要就是執行動畫。需要注意的就是有些情況需要配合move的動作。
自定義ItemAnimator後,直接為RecyclerView設定即可:
list.setItemAnimator(new FlyAnimator());
設定後如果呼叫了adapter的notifyItemRemoved函式就會執行remove的動效。
完整程式碼如下:
class FlyAnimator extends SimpleItemAnimator{
List<RecyclerView.ViewHolder> removeHolders = new ArrayList<>();
List<RecyclerView.ViewHolder> removeAnimators = new ArrayList<>();
List<RecyclerView.ViewHolder> moveHolders = new ArrayList<>();
List<RecyclerView.ViewHolder> moveAnimators = new ArrayList<>();
@Override
public boolean animateRemove(RecyclerView.ViewHolder holder) {
removeHolders.add(holder);
return true;
}
@Override
public boolean animateAdd(RecyclerView.ViewHolder holder) {
return false;
}
@Override
public boolean animateMove(RecyclerView.ViewHolder holder, int fromX, int fromY, int toX, int toY) {
holder.itemView.setTranslationY(fromY - toY);
moveHolders.add(holder);
return true;
}
@Override
public boolean animateChange(RecyclerView.ViewHolder oldHolder, RecyclerView.ViewHolder newHolder, int fromLeft, int fromTop, int toLeft, int toTop) {
return false;
}
@Override
public void runPendingAnimations() {
if(!removeHolders.isEmpty()) {
for(RecyclerView.ViewHolder holder : removeHolders) {
remove(holder);
}
removeHolders.clear();
}
if(!moveHolders.isEmpty()){
for(RecyclerView.ViewHolder holder : moveHolders) {
move(holder);
}
moveHolders.clear();
}
}
@Override
public void endAnimation(RecyclerView.ViewHolder item) {
}
@Override
public void endAnimations() {
}
@Override
public boolean isRunning() {
return !(removeHolders.isEmpty() && removeAnimators.isEmpty() && moveHolders.isEmpty() && moveAnimators.isEmpty());
}
private void remove(final RecyclerView.ViewHolder holder){
removeAnimators.add(holder);
TranslateAnimation animation = new TranslateAnimation(0, 1000, 0, 0);
animation.setDuration(500);
animation.setAnimationListener(new Animation.AnimationListener() {
@Override
public void onAnimationStart(Animation animation) {
dispatchRemoveStarting(holder);
}
@Override
public void onAnimationEnd(Animation animation) {
removeAnimators.remove(holder);
dispatchRemoveFinished(holder);
if(!isRunning()){
dispatchAnimationsFinished();
}
}
@Override
public void onAnimationRepeat(Animation animation) {
}
});
holder.itemView.startAnimation(animation);
}
private void move(final RecyclerView.ViewHolder holder){
moveAnimators.add(holder);
ObjectAnimator animator = ObjectAnimator.ofFloat(holder.itemView,
"translationY", holder.itemView.getTranslationY(), 0);
animator.setDuration(500);
animator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationStart(android.animation.Animator animation) {
dispatchMoveStarting(holder);
}
@Override
public void onAnimationEnd(android.animation.Animator animation) {
dispatchMoveFinished(holder);
moveAnimators.remove(holder);
if(!isRunning()) dispatchAnimationsFinished();
}
});
animator.start();
}
}
相關文章
- 實現漫天飛雪的動畫效果動畫
- iOS自定義UIView動畫效果iOSUIView動畫
- 自定義RecyclerView實現側滑刪除View
- Java 給PPT新增動畫效果(預設動畫/自定義動畫)Java動畫
- jQuery實現的滑鼠滑過連結出現自定義提示效果jQuery
- Android動畫效果之自定義ViewGroup新增布局動畫Android動畫View
- jQuery實現的自定義可以拖動的彈出層效果jQuery
- 自定義實現MIUI的拖動視差效果(阻尼效果)UI
- 自定義View:側滑選單動畫實現View動畫
- 一行程式碼實現自定義轉場動畫--iOS自定義轉場動畫集行程動畫iOS
- 自定義TabBar動畫效果 - 頁面轉場(Swift)tabBar動畫Swift
- 自定義view 之多個引導層動畫效果View動畫
- 【Android初級】如何實現一個有動畫效果的自定義下拉選單Android動畫
- RecycleView自定義ItemDecoration,實現時間軸效果View
- React實現動畫效果React動畫
- Javascript實現動畫效果JavaScript動畫
- Android自定義View——從零開始實現可暫停的旋轉動畫效果AndroidView動畫
- RecyclerView 裡的自定義 LayoutManager 的一種設計與實現View
- android利用RecyclerView+自定義View實現城市選擇介面AndroidView
- Android SeekBar 自定義thumb,thumb旋轉動畫效果Android動畫
- Android自定義View實現微信打飛機遊戲AndroidView遊戲
- Android自定義View實現文字輪播效果AndroidView
- RecyclerView 之使用 ItemTouchHelper 實現互動動畫View動畫
- jQuery動畫—自定義動畫animate()jQuery動畫
- 基於 RecyclerView 實現的歌詞滾動自定義控制元件View控制元件
- 自定義View 之 RecyclerView.ItemDecorationView
- RecyclerView之自定義LayoutManager和SnapHelperView
- RecyclerVieW自定義華麗的分割線View
- 自定義拖拽效果
- 自定義View:自定義屬性(自定義按鈕實現)View
- Flutter動畫實現粒子漂浮效果Flutter動畫
- 用JavaScript實現動畫效果 (轉)JavaScript動畫
- RecyclerView使用指南(五)—— 實現吸頂效果View
- 自定義過渡動畫動畫
- 自定義動畫方法animate()動畫
- 自定義波紋動畫動畫
- 【Jquery】jquery 自定義動畫jQuery動畫
- 關於RecyclerView.ItemDecoration的自定義View