Android 컨트롤-RecyclerView 시리즈 4(Item Animator)

1. Item Animator
실제 개발에서 우리는 자신의 인터페이스를 더욱 멋지게 만들고 애니메이션이라는 요소를 넣지 않으려고 한다. RecyclerView는 setItemAnimator(ItemAnimator) 설정을 통해 애니메이션 효과를 추가, 삭제, 이동, 변경할 수 있다.RecyclerView는 기본 ItemAnimator 구현 클래스인 DefaultItemAnimator를 제공합니다.
1.1 DefaultAnimator 분석
DefaultItemAnimator는 SimpleItemAnimator, SimpleItemAnimator는 ItemAnimator에서 상속됩니다.
먼저 ItemAnimator 클래스의 몇 가지 중요한 방법을 살펴보겠습니다.
  • animateAppearance(): ViewHolder가 화면에 나타날 때 호출됨(add 또는 move일 수 있음)
  • animateDisappearance(: ViewHolder가 화면에 사라질 때 호출됨(remove 또는move일 수 있음)
  • animatePersistence(): notifyItemChanged()와 notifyDataSetChanged()를 호출하지 않은 상태에서 레이아웃이 바뀌었을 때 호출됩니다.
  • animateChange(): notify ItemChanged () 또는 notify DataSetChanged () 를 현식으로 호출할 때 호출됩니다.
  • runPendingAnimations(): RecyclerView 애니메이션의 실행 방식은 바로 실행하는 것이 아니라 프레임마다 한 번씩 실행한다. 예를 들어 두 프레임 사이에 여러 개의 Item이 추가되면 실행할 애니메이션 Pending을 구성원 변수에 저장하고 다음 프레임과 함께 실행한다.이 방법이 실행되는 전제는 앞의 animate Xxx () 가true로 되돌아오는 것이다.
  • isRunning(): 애니메이션이 실행 중이거나 실행 중인지 여부
  • dispatchAnimationsFinished(): 모든 애니메이션이 실행되었을 때 호출됨
  • 위의 몇 가지 방법은 이해하기 어려울 수 있습니다. 안드로이드는 SimpleItemAnimator 클래스를 제공했고 이 클래스는 일련의 이해하기 쉬운 API를 제공합니다.
  • animateAdd(ViewHolder holder): Item이 추가될 때 호출됩니다.
  • animateMove(ViewHolder holder, int fromX, int fromY, int toX, int toY): Item이 이동할 때 호출됩니다.
  • animateRemove(ViewHolder holder): Item이 제거될 때 호출됩니다.
  • animateChange(ViewHolder oldHolder, ViewHolder newHolder, int fromLeft, int fromTop, int toLeft, int toTop): notify ItemChanged () 또는 notify DataSetChanged () 를 현식으로 호출할 때 호출됩니다.

  • 다음 네 가지 방법에 주의하십시오.
  • Xxx 애니메이션이 실행되기 전runPendingAnimations()에는 호출dispatchXxxStarting(holder)이 필요하고 실행이 끝난 후에는 호출dispatchXxxFinished(holder)이 필요합니다.
  • 이러한 방법의 내부는 실제적으로 애니메이션을 실행하는 코드를 쓰는 것이 아니라 애니메이션을 실행해야 하는 Item을 모두 구성원 변수에 저장하고 반환값은true로 되돌려준 다음runPendingAnimations()에서 함께 실행한다.

  • DefaultItemAnimator의 구성원 변수를 살펴보겠습니다.
    private ArrayList<ViewHolder> mPendingRemovals = new ArrayList();
        private ArrayList<ViewHolder> mPendingAdditions = new ArrayList();	//           add  
        private ArrayList<DefaultItemAnimator.MoveInfo> mPendingMoves = new ArrayList();
        private ArrayList<DefaultItemAnimator.ChangeInfo> mPendingChanges = new ArrayList();
        ArrayList<ArrayList<ViewHolder>> mAdditionsList = new ArrayList();	//         add  
        ArrayList<ArrayList<DefaultItemAnimator.MoveInfo>> mMovesList = new ArrayList();
        ArrayList<ArrayList<DefaultItemAnimator.ChangeInfo>> mChangesList = new ArrayList();
        ArrayList<ViewHolder> mAddAnimations = new ArrayList();	//         add  
        ArrayList<ViewHolder> mMoveAnimations = new ArrayList();
        ArrayList<ViewHolder> mRemoveAnimations = new ArrayList();
        ArrayList<ViewHolder> mChangeAnimations = new ArrayList();
    

    DefaultItemAnimator는 SimpleItemAnimateAdd () 방법을 실현했습니다. 이 방법은 이 item을 mPendingAdditions에 추가하고runPendingAnimations () 에서 실행할 때까지 기다리는 것입니다.
    public boolean animateAdd(ViewHolder holder) {
            this.resetAnimation(holder);	//        
            holder.itemView.setAlpha(0.0F);	//      View     
            this.mPendingAdditions.add(holder);
            return true;
        }
    

    이어서 runPendingAnimations()의 실현을 보면 이 방법은remove,move,change,add 애니메이션을 실행하는 것이다. 실행 순서는:remove 애니메이션이 가장 먼저 실행되고 그 다음에move와change가 병행하며 마지막은add 애니메이션이다.간소화하기 위해서 우리는remove,move,change 애니메이션의 실행 과정을 생략하고dd애니메이션을 실행하는 과정만 볼 것이다. 다음과 같다.
    public void runPendingAnimations() {
    	//1、          ,               。
         //2、  remove  
         //3、  move  
         //4、  change  , move      
         //5、  add  
         if (additionsPending) {
                    additions = new ArrayList();
                    additions.addAll(this.mPendingAdditions);
                    this.mAdditionsList.add(additions);
                    this.mPendingAdditions.clear();
                    adder = new Runnable() {
                        public void run() {
                            Iterator var1 = additions.iterator();
    
                            while(var1.hasNext()) {
                                ViewHolder holder = (ViewHolder)var1.next();
                                DefaultItemAnimator.this.animateAddImpl(holder);	//       
                            }
    
                            additions.clear();
                            DefaultItemAnimator.this.mAdditionsList.remove(additions);
                        }
                    };
                    if (!removalsPending && !movesPending && !changesPending) {
                        adder.run();
                    } else {
                        long removeDuration = removalsPending ? this.getRemoveDuration() : 0L;
                        long moveDuration = movesPending ? this.getMoveDuration() : 0L;
                        long changeDuration = changesPending ? this.getChangeDuration() : 0L;
                        long totalDelay = removeDuration + Math.max(moveDuration, changeDuration);
                        View view = ((ViewHolder)additions.get(0)).itemView;
                        ViewCompat.postOnAnimationDelayed(view, adder, totalDelay);
                    }
                }
    }
    

    dd 애니메이션을 실행할 때 외부에 새로운dd 애니메이션이 mPendingAdditions에 추가되어 실행add 애니메이션이 혼란스러워지지 않도록 mPendingAdditions의 내용을 국부 변수additions로 이동한 다음additions를 옮겨다니며 애니메이션을 실행합니다.
    runPendingAnimations ()에서 animateAddImpl ()는add 애니메이션을 실행하는 구체적인 방법입니다. 사실itemView의 투명도를 0에서 1로 바꾸는 것입니다. (animateAdd ()에서view의 투명도를 0으로 바꾸는 것) 은 다음과 같습니다.
    void animateAddImpl(final ViewHolder holder) {
            final View view = holder.itemView;
            final ViewPropertyAnimator animation = view.animate();
            this.mAddAnimations.add(holder);
            animation.alpha(1.0F).setDuration(this.getAddDuration()).setListener(new AnimatorListenerAdapter() {
                public void onAnimationStart(Animator animator) {
                    DefaultItemAnimator.this.dispatchAddStarting(holder);	//   add     
                }
    
                public void onAnimationCancel(Animator animator) {
                    view.setAlpha(1.0F);
                }
    
                public void onAnimationEnd(Animator animator) {
                    animation.setListener((AnimatorListener)null);
                    DefaultItemAnimator.this.dispatchAddFinished(holder);	//   add     
                    DefaultItemAnimator.this.mAddAnimations.remove(holder);
                    DefaultItemAnimator.this.dispatchFinishedWhenDone();	//         
                }
            }).start();
        }
    
    

    1.2 사용자 정의 ItemAnimator
    DefaultItemAnimator 클래스의 실현을 보면 사용자 정의 Item Animator가 비교적 번거로우므로 SimpleItemAnimator 클래스를 계승하고 한 무더기의 방법을 실현해야 한다.제3자 소스 라이브러리, 예를 들어recyclerview-animators
    recyclerview-animators는 FadeInAnimator,ScaleInAnimator 등 일련의 Animator를 제공했다.그 다음에 만약에 이 라이브러리에 마음에 드는 애니메이션이 없다면 이 라이브러리는 BaseItemAnimator 를 제공한다. 이 종류는 Simple Item Animator에서 계승되고 사용자 정의 Item Animator 코드를 봉인하여 사용자 정의 Item Animator를 더욱 편리하게 한다. 당신은 애니메이션 자체에 주목하기만 하면 된다.DefaultItemAnimator 코드를 구현하려면 다음과 같이 하십시오.
    public class DefaultItemAnimator extends BaseItemAnimator {
    
       public DefaultItemAnimator() {
       }
    
       public DefaultItemAnimator(Interpolator interpolator) {
         mInterpolator = interpolator;
       }
    
       @Override protected void animateRemoveImpl(final RecyclerView.ViewHolder holder) {
         ViewCompat.animate(holder.itemView)
             .alpha(0)
             .setDuration(getRemoveDuration())
             .setListener(new DefaultRemoveVpaListener(holder))
             .setStartDelay(getRemoveDelay(holder))
             .start();
       }
    
       @Override protected void preAnimateAddImpl(RecyclerView.ViewHolder holder) {
         ViewCompat.setAlpha(holder.itemView, 0); //      0
       }
    
       @Override protected void animateAddImpl(final RecyclerView.ViewHolder holder) {
         ViewCompat.animate(holder.itemView)
             .alpha(1)
             .setDuration(getAddDuration())
             .setListener(new DefaultAddVpaListener(holder))
             .setStartDelay(getAddDelay(holder))
             .start();
       }
     }
    

    RecyclerView의 Item Animator에 대해 흔히 볼 수 있는 구멍은 바로'플래시 문제'입니다.이 질문에 대한 설명은 Item 보기에 그림과 문자가 있고, 텍스트를 업데이트하고 notify Item Changed () 를 호출할 때, 텍스트가 바뀌면 그림이 깜빡입니다.이 문제는 notify Item Changed () 를 호출할 때Default Item Animator의 animate Change Impl () 를 호출하여change 애니메이션을 실행합니다. 이 애니메이션은 Item의 투명도를 0에서 1로 바꾸어 플래시를 만들 수 있습니다.
    해결 방법은 매우 간단하다.setadapter() 이전에 rv를 호출합니다((SimpleItemAnimator).getItemAnimator()).setSupportsChangeAnimations(false)는 change 애니메이션을 비활성화합니다.

    좋은 웹페이지 즐겨찾기