DefaultItemAnimator.java revision d7d27e9ebe5c7325e67e1a8af265378bd2056cad
1d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase/*
2d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase * Copyright (C) 2014 The Android Open Source Project
3d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase *
4d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase * Licensed under the Apache License, Version 2.0 (the "License");
5d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase * you may not use this file except in compliance with the License.
6d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase * You may obtain a copy of the License at
7d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase *
8d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase *      http://www.apache.org/licenses/LICENSE-2.0
9d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase *
10d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase * Unless required by applicable law or agreed to in writing, software
11d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase * distributed under the License is distributed on an "AS IS" BASIS,
12d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase * See the License for the specific language governing permissions and
14d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase * limitations under the License.
15d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase */
16d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haasepackage android.support.v7.widget;
17d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase
18d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haaseimport android.support.v4.view.ViewCompat;
19d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haaseimport android.support.v4.view.ViewPropertyAnimatorListener;
20d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haaseimport android.support.v7.widget.RecyclerView.ViewHolder;
21d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haaseimport android.view.View;
22d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase
23d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haaseimport java.util.ArrayList;
24d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase
25d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase/**
26d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase * This implementation of {@link RecyclerView.ItemAnimator} provides basic
27d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase * animations on remove, add, and move events that happen to the items in
28d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase * a RecyclerView. RecyclerView uses a DefaultItemAnimator by default.
29d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase *
30d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase * @see RecyclerView#setItemAnimator(RecyclerView.ItemAnimator)
31d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase */
32d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haasepublic class DefaultItemAnimator extends RecyclerView.ItemAnimator {
33d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase
34d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase    private ArrayList<ViewHolder> mPendingRemovals = new ArrayList<ViewHolder>();
35d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase    private ArrayList<ViewHolder> mPendingAdditions = new ArrayList<ViewHolder>();
36d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase    private ArrayList<MoveInfo> mPendingMoves = new ArrayList<MoveInfo>();
37d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase
38d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase    private ArrayList<ViewHolder> mAdditions = new ArrayList<ViewHolder>();
39d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase    private ArrayList<MoveInfo> mMoves = new ArrayList<MoveInfo>();
40d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase
41d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase    private ArrayList<ViewHolder> mAddAnimations = new ArrayList<ViewHolder>();
42d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase    private ArrayList<ViewHolder> mMoveAnimations = new ArrayList<ViewHolder>();
43d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase    private ArrayList<ViewHolder> mRemoveAnimations = new ArrayList<ViewHolder>();
44d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase
45d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase    private static class MoveInfo {
46d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        public ViewHolder holder;
47d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        public int fromX, fromY, toX, toY;
48d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase
49d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        private MoveInfo(ViewHolder holder, int fromX, int fromY, int toX, int toY) {
50d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase            this.holder = holder;
51d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase            this.fromX = fromX;
52d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase            this.fromY = fromY;
53d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase            this.toX = toX;
54d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase            this.toY = toY;
55d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        }
56d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase    }
57d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase
58d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase    @Override
59d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase    public void runPendingAnimations() {
60d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        boolean removalsPending = !mPendingRemovals.isEmpty();
61d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        boolean movesPending = !mPendingMoves.isEmpty();
62d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        boolean additionsPending = !mPendingAdditions.isEmpty();
63d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        if (!removalsPending && !movesPending && !additionsPending) {
64d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase            // nothing to animate
65d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase            return;
66d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        }
67d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        // First, remove stuff
68d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        for (ViewHolder holder : mPendingRemovals) {
69d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase            animateRemoveImpl(holder);
70d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        }
71d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        mPendingRemovals.clear();
72d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        // Next, move stuff
73d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        if (movesPending) {
74d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase            mMoves.addAll(mPendingMoves);
75d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase            mPendingMoves.clear();
76d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase            Runnable mover = new Runnable() {
77d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase                @Override
78d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase                public void run() {
79d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase                    for (MoveInfo moveInfo : mMoves) {
80d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase                        animateMoveImpl(moveInfo.holder, moveInfo.fromX, moveInfo.fromY,
81d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase                                moveInfo.toX, moveInfo.toY);
82d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase                    }
83d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase                    mMoves.clear();
84d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase                }
85d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase            };
86d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase            if (removalsPending) {
87d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase                View view = mMoves.get(0).holder.itemView;
88d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase                ViewCompat.postOnAnimationDelayed(view, mover, getRemoveDuration());
89d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase            } else {
90d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase                mover.run();
91d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase            }
92d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        }
93d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        // Next, add stuff
94d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        if (additionsPending) {
95d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase            mAdditions.addAll(mPendingAdditions);
96d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase            mPendingAdditions.clear();
97d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase            Runnable adder = new Runnable() {
98d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase                public void run() {
99d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase                    for (ViewHolder holder : mAdditions) {
100d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase                        animateAddImpl(holder);
101d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase                    }
102d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase                    mAdditions.clear();
103d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase                }
104d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase            };
105d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase            if (removalsPending || movesPending) {
106d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase                View view = mAdditions.get(0).itemView;
107d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase                ViewCompat.postOnAnimationDelayed(view, adder,
108d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase                        (removalsPending ? getRemoveDuration() : 0) +
109d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase                                (movesPending ? getMoveDuration() : 0));
110d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase            } else {
111d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase                adder.run();
112d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase            }
113d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        }
114d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase    }
115d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase
116d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase    @Override
117d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase    public boolean animateRemove(final ViewHolder holder) {
118d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        mPendingRemovals.add(holder);
119d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        return true;
120d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase    }
121d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase
122d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase    private void animateRemoveImpl(final ViewHolder holder) {
123d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        final View view = holder.itemView;
124d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        ViewCompat.animate(view).cancel();
125d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        ViewCompat.animate(view).setDuration(getRemoveDuration()).
126d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase                alpha(0).setListener(new VpaListenerAdapter() {
127d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase            @Override
128d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase            public void onAnimationEnd(View view) {
129d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase                ViewCompat.setAlpha(view, 1);
130d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase                dispatchRemoveFinished(holder);
131d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase                mRemoveAnimations.remove(holder);
132d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase                dispatchFinishedWhenDone();
133d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase            }
134d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        }).start();
135d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        mRemoveAnimations.add(holder);
136d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase    }
137d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase
138d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase    @Override
139d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase    public boolean animateAdd(final ViewHolder holder) {
140d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        ViewCompat.setAlpha(holder.itemView, 0);
141d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        mPendingAdditions.add(holder);
142d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        return true;
143d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase    }
144d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase
145d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase    private void animateAddImpl(final ViewHolder holder) {
146d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        final View view = holder.itemView;
147d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        ViewCompat.animate(view).cancel();
148d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        ViewCompat.animate(view).alpha(1).setDuration(getAddDuration()).
149d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase                setListener(new VpaListenerAdapter() {
150d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase                    @Override
151d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase                    public void onAnimationCancel(View view) {
152d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase                        ViewCompat.setAlpha(view, 1);
153d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase                    }
154d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase                    @Override
155d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase                    public void onAnimationEnd(View view) {
156d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase                        dispatchAddFinished(holder);
157d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase                        mAddAnimations.remove(holder);
158d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase                        dispatchFinishedWhenDone();
159d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase                    }
160d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase                }).start();
161d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        mAddAnimations.add(holder);
162d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase    }
163d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase
164d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase    @Override
165d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase    public boolean animateMove(final ViewHolder holder, int fromX, int fromY,
166d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase            int toX, int toY) {
167d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        final View view = holder.itemView;
168d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        int deltaX = toX - fromX;
169d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        int deltaY = toY - fromY;
170d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        if (deltaX == 0 && deltaY == 0) {
171d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase            dispatchMoveFinished(holder);
172d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase            return false;
173d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        }
174d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        if (deltaX != 0) {
175d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase            ViewCompat.setTranslationX(view, -deltaX);
176d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        }
177d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        if (deltaY != 0) {
178d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase            ViewCompat.setTranslationY(view, -deltaY);
179d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        }
180d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        mPendingMoves.add(new MoveInfo(holder, fromX, fromY, toX, toY));
181d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        return true;
182d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase    }
183d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase
184d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase    private void animateMoveImpl(final ViewHolder holder, int fromX, int fromY, int toX, int toY) {
185d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        final View view = holder.itemView;
186d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        final int deltaX = toX - fromX;
187d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        final int deltaY = toY - fromY;
188d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        ViewCompat.animate(view).cancel();
189d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        if (deltaX != 0) {
190d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase            ViewCompat.animate(view).translationX(0);
191d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        }
192d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        if (deltaY != 0) {
193d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase            ViewCompat.animate(view).translationY(0);
194d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        }
195d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        // TODO: make EndActions end listeners instead, since end actions aren't called when
196d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        // vpas are canceled (and can't end them. why?)
197d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        // need listener functionality in VPACompat for this. Ick.
198d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        ViewCompat.animate(view).setDuration(getMoveDuration()).setListener(new VpaListenerAdapter() {
199d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase            @Override
200d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase            public void onAnimationCancel(View view) {
201d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase                if (deltaX != 0) {
202d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase                    ViewCompat.setTranslationX(view, 0);
203d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase                }
204d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase                if (deltaY != 0) {
205d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase                    ViewCompat.setTranslationY(view, 0);
206d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase                }
207d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase            }
208d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase            @Override
209d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase            public void onAnimationEnd(View view) {
210d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase                dispatchMoveFinished(holder);
211d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase                mMoveAnimations.remove(holder);
212d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase                dispatchFinishedWhenDone();
213d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase            }
214d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        }).start();
215d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        mMoveAnimations.add(holder);
216d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase    }
217d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase
218d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase    @Override
219d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase    public void endAnimation(ViewHolder item) {
220d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        final View view = item.itemView;
221d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        ViewCompat.animate(view).cancel();
222d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        if (mMoveAnimations.contains(item)) {
223d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase            ViewCompat.setTranslationY(view, 0);
224d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase            ViewCompat.setTranslationX(view, 0);
225d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase            dispatchMoveFinished(item);
226d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase            mMoveAnimations.remove(item);
227d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        }
228d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        if (mRemoveAnimations.contains(item)) {
229d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase            ViewCompat.setAlpha(view, 1);
230d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase            dispatchRemoveFinished(item);
231d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase            mRemoveAnimations.remove(item);
232d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        }
233d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        if (mAddAnimations.contains(item)) {
234d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase            ViewCompat.setAlpha(view, 1);
235d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase            dispatchAddFinished(item);
236d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase            mAddAnimations.remove(item);
237d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        }
238d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        dispatchFinishedWhenDone();
239d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase    }
240d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase
241d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase    @Override
242d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase    public boolean isRunning() {
243d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        return (!mMoveAnimations.isEmpty() ||
244d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase                !mRemoveAnimations.isEmpty() ||
245d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase                !mAddAnimations.isEmpty() ||
246d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase                !mMoves.isEmpty() ||
247d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase                !mAdditions.isEmpty());
248d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase    }
249d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase
250d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase    /**
251d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase     * Check the state of currently pending and running animations. If there are none
252d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase     * pending/running, call {@link #dispatchAnimationsFinished()} to notify any
253d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase     * listeners.
254d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase     */
255d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase    private void dispatchFinishedWhenDone() {
256d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        if (!isRunning()) {
257d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase            dispatchAnimationsFinished();
258d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        }
259d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase    }
260d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase
261d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase    @Override
262d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase    public void endAnimations() {
263d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        if (!isRunning()) {
264d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase            return;
265d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        }
266d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        int count = mMoveAnimations.size();
267d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        for (int i = count - 1; i >= 0; i--) {
268d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase            ViewHolder item = mMoveAnimations.get(i);
269d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase            View view = item.itemView;
270d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase            ViewCompat.animate(view).cancel();
271d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase            ViewCompat.setTranslationY(view, 0);
272d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase            ViewCompat.setTranslationX(view, 0);
273d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase            dispatchMoveFinished(item);
274d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase            mMoveAnimations.remove(item);
275d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        }
276d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        count = mRemoveAnimations.size();
277d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        for (int i = count - 1; i >= 0; i--) {
278d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase            ViewHolder item = mRemoveAnimations.get(i);
279d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase            View view = item.itemView;
280d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase            ViewCompat.animate(view).cancel();
281d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase            ViewCompat.setAlpha(view, 1);
282d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase            dispatchRemoveFinished(item);
283d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase            mRemoveAnimations.remove(item);
284d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        }
285d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        count = mAddAnimations.size();
286d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        for (int i = count - 1; i >= 0; i--) {
287d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase            ViewHolder item = mAddAnimations.get(i);
288d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase            View view = item.itemView;
289d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase            ViewCompat.animate(view).cancel();
290d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase            ViewCompat.setAlpha(view, 1);
291d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase            dispatchAddFinished(item);
292d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase            mAddAnimations.remove(item);
293d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        }
294d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        mMoves.clear();
295d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        mAdditions.clear();
296d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        dispatchAnimationsFinished();
297d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase    }
298d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase
299d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase    private static class VpaListenerAdapter implements ViewPropertyAnimatorListener {
300d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        @Override
301d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        public void onAnimationStart(View view) {}
302d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase
303d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        @Override
304d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        public void onAnimationEnd(View view) {}
305d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase
306d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        @Override
307d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        public void onAnimationCancel(View view) {}
308d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase    };
309d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase}
310