DefaultItemAnimator.java revision 549bbdfca3cffe64fd3ef69723a54037df326689
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;
19a29fe6d4967a704799dc83d35ba80e426e9512cfYigit Boyarimport android.support.v4.view.ViewPropertyAnimatorCompat;
20d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haaseimport android.support.v4.view.ViewPropertyAnimatorListener;
21d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haaseimport android.support.v7.widget.RecyclerView.ViewHolder;
22d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haaseimport android.view.View;
23d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase
24d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haaseimport java.util.ArrayList;
25a29fe6d4967a704799dc83d35ba80e426e9512cfYigit Boyarimport java.util.List;
26d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase
27d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase/**
28d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase * This implementation of {@link RecyclerView.ItemAnimator} provides basic
29d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase * animations on remove, add, and move events that happen to the items in
30d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase * a RecyclerView. RecyclerView uses a DefaultItemAnimator by default.
31d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase *
32d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase * @see RecyclerView#setItemAnimator(RecyclerView.ItemAnimator)
33d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase */
34d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haasepublic class DefaultItemAnimator extends RecyclerView.ItemAnimator {
35a29fe6d4967a704799dc83d35ba80e426e9512cfYigit Boyar    private static final boolean DEBUG = false;
36d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase
37d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase    private ArrayList<ViewHolder> mPendingRemovals = new ArrayList<ViewHolder>();
38d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase    private ArrayList<ViewHolder> mPendingAdditions = new ArrayList<ViewHolder>();
39d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase    private ArrayList<MoveInfo> mPendingMoves = new ArrayList<MoveInfo>();
40235114f0ea0ae165e74a478f39bfc586392c53aaChet Haase    private ArrayList<ChangeInfo> mPendingChanges = new ArrayList<ChangeInfo>();
41d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase
420e0bfdb790fd9477e3531a1db92c3377057f83b7Chet Haase    private ArrayList<ArrayList<ViewHolder>> mAdditionsList =
430e0bfdb790fd9477e3531a1db92c3377057f83b7Chet Haase            new ArrayList<ArrayList<ViewHolder>>();
440e0bfdb790fd9477e3531a1db92c3377057f83b7Chet Haase    private ArrayList<ArrayList<MoveInfo>> mMovesList = new ArrayList<ArrayList<MoveInfo>>();
450e0bfdb790fd9477e3531a1db92c3377057f83b7Chet Haase    private ArrayList<ArrayList<ChangeInfo>> mChangesList = new ArrayList<ArrayList<ChangeInfo>>();
46d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase
47d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase    private ArrayList<ViewHolder> mAddAnimations = new ArrayList<ViewHolder>();
48d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase    private ArrayList<ViewHolder> mMoveAnimations = new ArrayList<ViewHolder>();
49d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase    private ArrayList<ViewHolder> mRemoveAnimations = new ArrayList<ViewHolder>();
50a29fe6d4967a704799dc83d35ba80e426e9512cfYigit Boyar    private ArrayList<ViewHolder> mChangeAnimations = new ArrayList<ViewHolder>();
51d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase
52d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase    private static class MoveInfo {
53d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        public ViewHolder holder;
54d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        public int fromX, fromY, toX, toY;
55d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase
56d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        private MoveInfo(ViewHolder holder, int fromX, int fromY, int toX, int toY) {
57d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase            this.holder = holder;
58d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase            this.fromX = fromX;
59d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase            this.fromY = fromY;
60d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase            this.toX = toX;
61d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase            this.toY = toY;
62d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        }
63d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase    }
64d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase
65235114f0ea0ae165e74a478f39bfc586392c53aaChet Haase    private static class ChangeInfo {
66235114f0ea0ae165e74a478f39bfc586392c53aaChet Haase        public ViewHolder oldHolder, newHolder;
67a29fe6d4967a704799dc83d35ba80e426e9512cfYigit Boyar        public int fromX, fromY, toX, toY;
68235114f0ea0ae165e74a478f39bfc586392c53aaChet Haase        private ChangeInfo(ViewHolder oldHolder, ViewHolder newHolder) {
69235114f0ea0ae165e74a478f39bfc586392c53aaChet Haase            this.oldHolder = oldHolder;
70235114f0ea0ae165e74a478f39bfc586392c53aaChet Haase            this.newHolder = newHolder;
71235114f0ea0ae165e74a478f39bfc586392c53aaChet Haase        }
72a29fe6d4967a704799dc83d35ba80e426e9512cfYigit Boyar
73a29fe6d4967a704799dc83d35ba80e426e9512cfYigit Boyar        private ChangeInfo(ViewHolder oldHolder, ViewHolder newHolder,
74a29fe6d4967a704799dc83d35ba80e426e9512cfYigit Boyar                int fromX, int fromY, int toX, int toY) {
75a29fe6d4967a704799dc83d35ba80e426e9512cfYigit Boyar            this(oldHolder, newHolder);
76a29fe6d4967a704799dc83d35ba80e426e9512cfYigit Boyar            this.fromX = fromX;
77a29fe6d4967a704799dc83d35ba80e426e9512cfYigit Boyar            this.fromY = fromY;
78a29fe6d4967a704799dc83d35ba80e426e9512cfYigit Boyar            this.toX = toX;
79a29fe6d4967a704799dc83d35ba80e426e9512cfYigit Boyar            this.toY = toY;
80a29fe6d4967a704799dc83d35ba80e426e9512cfYigit Boyar        }
81a29fe6d4967a704799dc83d35ba80e426e9512cfYigit Boyar
82a29fe6d4967a704799dc83d35ba80e426e9512cfYigit Boyar        @Override
83a29fe6d4967a704799dc83d35ba80e426e9512cfYigit Boyar        public String toString() {
84a29fe6d4967a704799dc83d35ba80e426e9512cfYigit Boyar            return "ChangeInfo{" +
85a29fe6d4967a704799dc83d35ba80e426e9512cfYigit Boyar                    "oldHolder=" + oldHolder +
86a29fe6d4967a704799dc83d35ba80e426e9512cfYigit Boyar                    ", newHolder=" + newHolder +
87a29fe6d4967a704799dc83d35ba80e426e9512cfYigit Boyar                    ", fromX=" + fromX +
88a29fe6d4967a704799dc83d35ba80e426e9512cfYigit Boyar                    ", fromY=" + fromY +
89a29fe6d4967a704799dc83d35ba80e426e9512cfYigit Boyar                    ", toX=" + toX +
90a29fe6d4967a704799dc83d35ba80e426e9512cfYigit Boyar                    ", toY=" + toY +
91a29fe6d4967a704799dc83d35ba80e426e9512cfYigit Boyar                    '}';
92a29fe6d4967a704799dc83d35ba80e426e9512cfYigit Boyar        }
93235114f0ea0ae165e74a478f39bfc586392c53aaChet Haase    }
94235114f0ea0ae165e74a478f39bfc586392c53aaChet Haase
95d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase    @Override
96d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase    public void runPendingAnimations() {
97d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        boolean removalsPending = !mPendingRemovals.isEmpty();
98d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        boolean movesPending = !mPendingMoves.isEmpty();
99235114f0ea0ae165e74a478f39bfc586392c53aaChet Haase        boolean changesPending = !mPendingChanges.isEmpty();
100d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        boolean additionsPending = !mPendingAdditions.isEmpty();
101a29fe6d4967a704799dc83d35ba80e426e9512cfYigit Boyar        if (!removalsPending && !movesPending && !additionsPending && !changesPending) {
102d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase            // nothing to animate
103d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase            return;
104d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        }
105d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        // First, remove stuff
106d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        for (ViewHolder holder : mPendingRemovals) {
107d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase            animateRemoveImpl(holder);
108d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        }
109d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        mPendingRemovals.clear();
110d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        // Next, move stuff
111d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        if (movesPending) {
1120e0bfdb790fd9477e3531a1db92c3377057f83b7Chet Haase            final ArrayList<MoveInfo> moves = new ArrayList<MoveInfo>();
1130e0bfdb790fd9477e3531a1db92c3377057f83b7Chet Haase            moves.addAll(mPendingMoves);
1140e0bfdb790fd9477e3531a1db92c3377057f83b7Chet Haase            mMovesList.add(moves);
115d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase            mPendingMoves.clear();
116d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase            Runnable mover = new Runnable() {
117d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase                @Override
118d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase                public void run() {
1190e0bfdb790fd9477e3531a1db92c3377057f83b7Chet Haase                    for (MoveInfo moveInfo : moves) {
120d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase                        animateMoveImpl(moveInfo.holder, moveInfo.fromX, moveInfo.fromY,
121d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase                                moveInfo.toX, moveInfo.toY);
122d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase                    }
1230e0bfdb790fd9477e3531a1db92c3377057f83b7Chet Haase                    moves.clear();
1240e0bfdb790fd9477e3531a1db92c3377057f83b7Chet Haase                    mMovesList.remove(moves);
125d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase                }
126d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase            };
127d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase            if (removalsPending) {
1280e0bfdb790fd9477e3531a1db92c3377057f83b7Chet Haase                View view = moves.get(0).holder.itemView;
129d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase                ViewCompat.postOnAnimationDelayed(view, mover, getRemoveDuration());
130d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase            } else {
131d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase                mover.run();
132d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase            }
133d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        }
134235114f0ea0ae165e74a478f39bfc586392c53aaChet Haase        // Next, change stuff, to run in parallel with move animations
135235114f0ea0ae165e74a478f39bfc586392c53aaChet Haase        if (changesPending) {
1360e0bfdb790fd9477e3531a1db92c3377057f83b7Chet Haase            final ArrayList<ChangeInfo> changes = new ArrayList<ChangeInfo>();
1370e0bfdb790fd9477e3531a1db92c3377057f83b7Chet Haase            changes.addAll(mPendingChanges);
1380e0bfdb790fd9477e3531a1db92c3377057f83b7Chet Haase            mChangesList.add(changes);
139235114f0ea0ae165e74a478f39bfc586392c53aaChet Haase            mPendingChanges.clear();
140235114f0ea0ae165e74a478f39bfc586392c53aaChet Haase            Runnable changer = new Runnable() {
141235114f0ea0ae165e74a478f39bfc586392c53aaChet Haase                @Override
142235114f0ea0ae165e74a478f39bfc586392c53aaChet Haase                public void run() {
1430e0bfdb790fd9477e3531a1db92c3377057f83b7Chet Haase                    for (ChangeInfo change : changes) {
144235114f0ea0ae165e74a478f39bfc586392c53aaChet Haase                        animateChangeImpl(change);
145235114f0ea0ae165e74a478f39bfc586392c53aaChet Haase                    }
1460e0bfdb790fd9477e3531a1db92c3377057f83b7Chet Haase                    changes.clear();
1470e0bfdb790fd9477e3531a1db92c3377057f83b7Chet Haase                    mChangesList.remove(changes);
148235114f0ea0ae165e74a478f39bfc586392c53aaChet Haase                }
149235114f0ea0ae165e74a478f39bfc586392c53aaChet Haase            };
150235114f0ea0ae165e74a478f39bfc586392c53aaChet Haase            if (removalsPending) {
1510e0bfdb790fd9477e3531a1db92c3377057f83b7Chet Haase                ViewHolder holder = changes.get(0).oldHolder;
152235114f0ea0ae165e74a478f39bfc586392c53aaChet Haase                ViewCompat.postOnAnimationDelayed(holder.itemView, changer, getRemoveDuration());
153235114f0ea0ae165e74a478f39bfc586392c53aaChet Haase            } else {
154235114f0ea0ae165e74a478f39bfc586392c53aaChet Haase                changer.run();
155235114f0ea0ae165e74a478f39bfc586392c53aaChet Haase            }
156235114f0ea0ae165e74a478f39bfc586392c53aaChet Haase        }
157d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        // Next, add stuff
158d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        if (additionsPending) {
1590e0bfdb790fd9477e3531a1db92c3377057f83b7Chet Haase            final ArrayList<ViewHolder> additions = new ArrayList<ViewHolder>();
1600e0bfdb790fd9477e3531a1db92c3377057f83b7Chet Haase            additions.addAll(mPendingAdditions);
1610e0bfdb790fd9477e3531a1db92c3377057f83b7Chet Haase            mAdditionsList.add(additions);
162d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase            mPendingAdditions.clear();
163d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase            Runnable adder = new Runnable() {
164d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase                public void run() {
1650e0bfdb790fd9477e3531a1db92c3377057f83b7Chet Haase                    for (ViewHolder holder : additions) {
166d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase                        animateAddImpl(holder);
167d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase                    }
1680e0bfdb790fd9477e3531a1db92c3377057f83b7Chet Haase                    additions.clear();
1690e0bfdb790fd9477e3531a1db92c3377057f83b7Chet Haase                    mAdditionsList.remove(additions);
170d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase                }
171d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase            };
172549bbdfca3cffe64fd3ef69723a54037df326689Chet Haase            if (removalsPending || movesPending || changesPending) {
173235114f0ea0ae165e74a478f39bfc586392c53aaChet Haase                long removeDuration = removalsPending ? getRemoveDuration() : 0;
174235114f0ea0ae165e74a478f39bfc586392c53aaChet Haase                long moveDuration = movesPending ? getMoveDuration() : 0;
175235114f0ea0ae165e74a478f39bfc586392c53aaChet Haase                long changeDuration = changesPending ? getChangeDuration() : 0;
176235114f0ea0ae165e74a478f39bfc586392c53aaChet Haase                long totalDelay = removeDuration + Math.max(moveDuration, changeDuration);
1770e0bfdb790fd9477e3531a1db92c3377057f83b7Chet Haase                View view = additions.get(0).itemView;
178235114f0ea0ae165e74a478f39bfc586392c53aaChet Haase                ViewCompat.postOnAnimationDelayed(view, adder, totalDelay);
179d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase            } else {
180d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase                adder.run();
181d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase            }
182d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        }
183d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase    }
184d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase
185d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase    @Override
186d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase    public boolean animateRemove(final ViewHolder holder) {
187504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar        endAnimation(holder);
188d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        mPendingRemovals.add(holder);
189d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        return true;
190d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase    }
191d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase
192d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase    private void animateRemoveImpl(final ViewHolder holder) {
193d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        final View view = holder.itemView;
19407715e8dcfa3e9fcd6c3e7727f61ca41b50e5763Dake Gu        final ViewPropertyAnimatorCompat animation = ViewCompat.animate(view);
19507715e8dcfa3e9fcd6c3e7727f61ca41b50e5763Dake Gu        animation.setDuration(getRemoveDuration())
19607715e8dcfa3e9fcd6c3e7727f61ca41b50e5763Dake Gu                .alpha(0).setListener(new VpaListenerAdapter() {
197d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase            @Override
198e321eb5c831282c92a28a483692d8520b766a0a5Chet Haase            public void onAnimationStart(View view) {
199e321eb5c831282c92a28a483692d8520b766a0a5Chet Haase                dispatchRemoveStarting(holder);
200e321eb5c831282c92a28a483692d8520b766a0a5Chet Haase            }
201e321eb5c831282c92a28a483692d8520b766a0a5Chet Haase            @Override
202d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase            public void onAnimationEnd(View view) {
20307715e8dcfa3e9fcd6c3e7727f61ca41b50e5763Dake Gu                animation.setListener(null);
204d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase                ViewCompat.setAlpha(view, 1);
205d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase                dispatchRemoveFinished(holder);
206d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase                mRemoveAnimations.remove(holder);
207d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase                dispatchFinishedWhenDone();
208d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase            }
209d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        }).start();
210d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        mRemoveAnimations.add(holder);
211d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase    }
212d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase
213d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase    @Override
214d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase    public boolean animateAdd(final ViewHolder holder) {
215504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar        endAnimation(holder);
216d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        ViewCompat.setAlpha(holder.itemView, 0);
217d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        mPendingAdditions.add(holder);
218d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        return true;
219d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase    }
220d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase
221d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase    private void animateAddImpl(final ViewHolder holder) {
222d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        final View view = holder.itemView;
223a29fe6d4967a704799dc83d35ba80e426e9512cfYigit Boyar        mAddAnimations.add(holder);
22407715e8dcfa3e9fcd6c3e7727f61ca41b50e5763Dake Gu        final ViewPropertyAnimatorCompat animation = ViewCompat.animate(view);
22507715e8dcfa3e9fcd6c3e7727f61ca41b50e5763Dake Gu        animation.alpha(1).setDuration(getAddDuration()).
226d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase                setListener(new VpaListenerAdapter() {
227d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase                    @Override
228e321eb5c831282c92a28a483692d8520b766a0a5Chet Haase                    public void onAnimationStart(View view) {
229e321eb5c831282c92a28a483692d8520b766a0a5Chet Haase                        dispatchAddStarting(holder);
230e321eb5c831282c92a28a483692d8520b766a0a5Chet Haase                    }
231e321eb5c831282c92a28a483692d8520b766a0a5Chet Haase                    @Override
232d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase                    public void onAnimationCancel(View view) {
233d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase                        ViewCompat.setAlpha(view, 1);
234d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase                    }
235c35968d173f900d8024bdf38174e2225c9a7f311Chet Haase
236d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase                    @Override
237d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase                    public void onAnimationEnd(View view) {
23807715e8dcfa3e9fcd6c3e7727f61ca41b50e5763Dake Gu                        animation.setListener(null);
239d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase                        dispatchAddFinished(holder);
240d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase                        mAddAnimations.remove(holder);
241d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase                        dispatchFinishedWhenDone();
242d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase                    }
243d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase                }).start();
244d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase    }
245d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase
246d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase    @Override
247d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase    public boolean animateMove(final ViewHolder holder, int fromX, int fromY,
248d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase            int toX, int toY) {
249d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        final View view = holder.itemView;
250504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar        fromX += ViewCompat.getTranslationX(holder.itemView);
251504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar        fromY += ViewCompat.getTranslationY(holder.itemView);
252504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar        endAnimation(holder);
253d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        int deltaX = toX - fromX;
254d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        int deltaY = toY - fromY;
255d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        if (deltaX == 0 && deltaY == 0) {
256d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase            dispatchMoveFinished(holder);
257d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase            return false;
258d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        }
259d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        if (deltaX != 0) {
260d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase            ViewCompat.setTranslationX(view, -deltaX);
261d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        }
262d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        if (deltaY != 0) {
263d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase            ViewCompat.setTranslationY(view, -deltaY);
264d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        }
265d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        mPendingMoves.add(new MoveInfo(holder, fromX, fromY, toX, toY));
266d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        return true;
267d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase    }
268d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase
269d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase    private void animateMoveImpl(final ViewHolder holder, int fromX, int fromY, int toX, int toY) {
270d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        final View view = holder.itemView;
271d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        final int deltaX = toX - fromX;
272d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        final int deltaY = toY - fromY;
273d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        if (deltaX != 0) {
274d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase            ViewCompat.animate(view).translationX(0);
275d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        }
276d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        if (deltaY != 0) {
277d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase            ViewCompat.animate(view).translationY(0);
278d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        }
279d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        // TODO: make EndActions end listeners instead, since end actions aren't called when
280d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        // vpas are canceled (and can't end them. why?)
281d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        // need listener functionality in VPACompat for this. Ick.
282a29fe6d4967a704799dc83d35ba80e426e9512cfYigit Boyar        mMoveAnimations.add(holder);
28307715e8dcfa3e9fcd6c3e7727f61ca41b50e5763Dake Gu        final ViewPropertyAnimatorCompat animation = ViewCompat.animate(view);
28407715e8dcfa3e9fcd6c3e7727f61ca41b50e5763Dake Gu        animation.setDuration(getMoveDuration()).setListener(new VpaListenerAdapter() {
285d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase            @Override
286e321eb5c831282c92a28a483692d8520b766a0a5Chet Haase            public void onAnimationStart(View view) {
287e321eb5c831282c92a28a483692d8520b766a0a5Chet Haase                dispatchMoveStarting(holder);
288e321eb5c831282c92a28a483692d8520b766a0a5Chet Haase            }
289e321eb5c831282c92a28a483692d8520b766a0a5Chet Haase            @Override
290d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase            public void onAnimationCancel(View view) {
291d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase                if (deltaX != 0) {
292d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase                    ViewCompat.setTranslationX(view, 0);
293d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase                }
294d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase                if (deltaY != 0) {
295d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase                    ViewCompat.setTranslationY(view, 0);
296d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase                }
297d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase            }
298d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase            @Override
299d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase            public void onAnimationEnd(View view) {
30007715e8dcfa3e9fcd6c3e7727f61ca41b50e5763Dake Gu                animation.setListener(null);
301d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase                dispatchMoveFinished(holder);
302d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase                mMoveAnimations.remove(holder);
303d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase                dispatchFinishedWhenDone();
304d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase            }
305d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        }).start();
306d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase    }
307d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase
308d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase    @Override
309a29fe6d4967a704799dc83d35ba80e426e9512cfYigit Boyar    public boolean animateChange(ViewHolder oldHolder, ViewHolder newHolder,
310a29fe6d4967a704799dc83d35ba80e426e9512cfYigit Boyar            int fromX, int fromY, int toX, int toY) {
311a29fe6d4967a704799dc83d35ba80e426e9512cfYigit Boyar        final float prevTranslationX = ViewCompat.getTranslationX(oldHolder.itemView);
312a29fe6d4967a704799dc83d35ba80e426e9512cfYigit Boyar        final float prevTranslationY = ViewCompat.getTranslationY(oldHolder.itemView);
313a29fe6d4967a704799dc83d35ba80e426e9512cfYigit Boyar        final float prevAlpha = ViewCompat.getAlpha(oldHolder.itemView);
314504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar        endAnimation(oldHolder);
315a29fe6d4967a704799dc83d35ba80e426e9512cfYigit Boyar        int deltaX = (int) (toX - fromX - prevTranslationX);
316a29fe6d4967a704799dc83d35ba80e426e9512cfYigit Boyar        int deltaY = (int) (toY - fromY - prevTranslationY);
317a29fe6d4967a704799dc83d35ba80e426e9512cfYigit Boyar        // recover prev translation state after ending animation
318a29fe6d4967a704799dc83d35ba80e426e9512cfYigit Boyar        ViewCompat.setTranslationX(oldHolder.itemView, prevTranslationX);
319a29fe6d4967a704799dc83d35ba80e426e9512cfYigit Boyar        ViewCompat.setTranslationY(oldHolder.itemView, prevTranslationY);
320a29fe6d4967a704799dc83d35ba80e426e9512cfYigit Boyar        ViewCompat.setAlpha(oldHolder.itemView, prevAlpha);
321235114f0ea0ae165e74a478f39bfc586392c53aaChet Haase        if (newHolder != null && newHolder.itemView != null) {
322a29fe6d4967a704799dc83d35ba80e426e9512cfYigit Boyar            // carry over translation values
323504c54ea52c1b2aae6f8f4ae128f1dcaac7e3f6aYigit Boyar            endAnimation(newHolder);
324a29fe6d4967a704799dc83d35ba80e426e9512cfYigit Boyar            ViewCompat.setTranslationX(newHolder.itemView, -deltaX);
325a29fe6d4967a704799dc83d35ba80e426e9512cfYigit Boyar            ViewCompat.setTranslationY(newHolder.itemView, -deltaY);
326235114f0ea0ae165e74a478f39bfc586392c53aaChet Haase            ViewCompat.setAlpha(newHolder.itemView, 0);
327235114f0ea0ae165e74a478f39bfc586392c53aaChet Haase        }
328a29fe6d4967a704799dc83d35ba80e426e9512cfYigit Boyar        mPendingChanges.add(new ChangeInfo(oldHolder, newHolder, fromX, fromY, toX, toY));
329235114f0ea0ae165e74a478f39bfc586392c53aaChet Haase        return true;
330235114f0ea0ae165e74a478f39bfc586392c53aaChet Haase    }
331235114f0ea0ae165e74a478f39bfc586392c53aaChet Haase
332235114f0ea0ae165e74a478f39bfc586392c53aaChet Haase    private void animateChangeImpl(final ChangeInfo changeInfo) {
333235114f0ea0ae165e74a478f39bfc586392c53aaChet Haase        final ViewHolder holder = changeInfo.oldHolder;
334235114f0ea0ae165e74a478f39bfc586392c53aaChet Haase        final View view = holder.itemView;
335235114f0ea0ae165e74a478f39bfc586392c53aaChet Haase        final ViewHolder newHolder = changeInfo.newHolder;
336235114f0ea0ae165e74a478f39bfc586392c53aaChet Haase        final View newView = newHolder != null ? newHolder.itemView : null;
337a29fe6d4967a704799dc83d35ba80e426e9512cfYigit Boyar        mChangeAnimations.add(changeInfo.oldHolder);
338a29fe6d4967a704799dc83d35ba80e426e9512cfYigit Boyar
33907715e8dcfa3e9fcd6c3e7727f61ca41b50e5763Dake Gu        final ViewPropertyAnimatorCompat oldViewAnim = ViewCompat.animate(view).setDuration(
340a29fe6d4967a704799dc83d35ba80e426e9512cfYigit Boyar                getChangeDuration());
341a29fe6d4967a704799dc83d35ba80e426e9512cfYigit Boyar        oldViewAnim.translationX(changeInfo.toX - changeInfo.fromX);
342a29fe6d4967a704799dc83d35ba80e426e9512cfYigit Boyar        oldViewAnim.translationY(changeInfo.toY - changeInfo.fromY);
343a29fe6d4967a704799dc83d35ba80e426e9512cfYigit Boyar        oldViewAnim.alpha(0).setListener(new VpaListenerAdapter() {
344235114f0ea0ae165e74a478f39bfc586392c53aaChet Haase            @Override
345e321eb5c831282c92a28a483692d8520b766a0a5Chet Haase            public void onAnimationStart(View view) {
346e321eb5c831282c92a28a483692d8520b766a0a5Chet Haase                dispatchChangeStarting(changeInfo.oldHolder, true);
347e321eb5c831282c92a28a483692d8520b766a0a5Chet Haase            }
348e321eb5c831282c92a28a483692d8520b766a0a5Chet Haase            @Override
349235114f0ea0ae165e74a478f39bfc586392c53aaChet Haase            public void onAnimationEnd(View view) {
35007715e8dcfa3e9fcd6c3e7727f61ca41b50e5763Dake Gu                oldViewAnim.setListener(null);
351235114f0ea0ae165e74a478f39bfc586392c53aaChet Haase                ViewCompat.setAlpha(view, 1);
352a29fe6d4967a704799dc83d35ba80e426e9512cfYigit Boyar                ViewCompat.setTranslationX(view, 0);
353a29fe6d4967a704799dc83d35ba80e426e9512cfYigit Boyar                ViewCompat.setTranslationY(view, 0);
354e321eb5c831282c92a28a483692d8520b766a0a5Chet Haase                dispatchChangeFinished(changeInfo.oldHolder, true);
355a29fe6d4967a704799dc83d35ba80e426e9512cfYigit Boyar                mChangeAnimations.remove(changeInfo.oldHolder);
356235114f0ea0ae165e74a478f39bfc586392c53aaChet Haase                dispatchFinishedWhenDone();
357235114f0ea0ae165e74a478f39bfc586392c53aaChet Haase            }
358235114f0ea0ae165e74a478f39bfc586392c53aaChet Haase        }).start();
359235114f0ea0ae165e74a478f39bfc586392c53aaChet Haase        if (newView != null) {
360a29fe6d4967a704799dc83d35ba80e426e9512cfYigit Boyar            mChangeAnimations.add(changeInfo.newHolder);
36107715e8dcfa3e9fcd6c3e7727f61ca41b50e5763Dake Gu            final ViewPropertyAnimatorCompat newViewAnimation = ViewCompat.animate(newView);
362a29fe6d4967a704799dc83d35ba80e426e9512cfYigit Boyar            newViewAnimation.translationX(0).translationY(0).setDuration(getChangeDuration()).
363235114f0ea0ae165e74a478f39bfc586392c53aaChet Haase                    alpha(1).setListener(new VpaListenerAdapter() {
364235114f0ea0ae165e74a478f39bfc586392c53aaChet Haase                @Override
365e321eb5c831282c92a28a483692d8520b766a0a5Chet Haase                public void onAnimationStart(View view) {
366e321eb5c831282c92a28a483692d8520b766a0a5Chet Haase                    dispatchChangeStarting(changeInfo.newHolder, false);
367e321eb5c831282c92a28a483692d8520b766a0a5Chet Haase                }
368e321eb5c831282c92a28a483692d8520b766a0a5Chet Haase                @Override
369235114f0ea0ae165e74a478f39bfc586392c53aaChet Haase                public void onAnimationEnd(View view) {
37007715e8dcfa3e9fcd6c3e7727f61ca41b50e5763Dake Gu                    newViewAnimation.setListener(null);
371235114f0ea0ae165e74a478f39bfc586392c53aaChet Haase                    ViewCompat.setAlpha(newView, 1);
372a29fe6d4967a704799dc83d35ba80e426e9512cfYigit Boyar                    ViewCompat.setTranslationX(newView, 0);
373a29fe6d4967a704799dc83d35ba80e426e9512cfYigit Boyar                    ViewCompat.setTranslationY(newView, 0);
374e321eb5c831282c92a28a483692d8520b766a0a5Chet Haase                    dispatchChangeFinished(changeInfo.newHolder, false);
375a29fe6d4967a704799dc83d35ba80e426e9512cfYigit Boyar                    mChangeAnimations.remove(changeInfo.newHolder);
376a29fe6d4967a704799dc83d35ba80e426e9512cfYigit Boyar                    dispatchFinishedWhenDone();
377235114f0ea0ae165e74a478f39bfc586392c53aaChet Haase                }
378235114f0ea0ae165e74a478f39bfc586392c53aaChet Haase            }).start();
379235114f0ea0ae165e74a478f39bfc586392c53aaChet Haase        }
380a29fe6d4967a704799dc83d35ba80e426e9512cfYigit Boyar    }
381a29fe6d4967a704799dc83d35ba80e426e9512cfYigit Boyar
382a29fe6d4967a704799dc83d35ba80e426e9512cfYigit Boyar    private void endChangeAnimation(List<ChangeInfo> infoList, ViewHolder item) {
383a29fe6d4967a704799dc83d35ba80e426e9512cfYigit Boyar        for (int i = infoList.size() - 1; i >= 0; i--) {
384a29fe6d4967a704799dc83d35ba80e426e9512cfYigit Boyar            ChangeInfo changeInfo = infoList.get(i);
385a29fe6d4967a704799dc83d35ba80e426e9512cfYigit Boyar            if (endChangeAnimationIfNecessary(changeInfo, item)) {
386a29fe6d4967a704799dc83d35ba80e426e9512cfYigit Boyar                if (changeInfo.oldHolder == null && changeInfo.newHolder == null) {
387a29fe6d4967a704799dc83d35ba80e426e9512cfYigit Boyar                    infoList.remove(changeInfo);
388a29fe6d4967a704799dc83d35ba80e426e9512cfYigit Boyar                }
389a29fe6d4967a704799dc83d35ba80e426e9512cfYigit Boyar            }
390a29fe6d4967a704799dc83d35ba80e426e9512cfYigit Boyar        }
391a29fe6d4967a704799dc83d35ba80e426e9512cfYigit Boyar    }
392a29fe6d4967a704799dc83d35ba80e426e9512cfYigit Boyar
393a29fe6d4967a704799dc83d35ba80e426e9512cfYigit Boyar    private void endChangeAnimationIfNecessary(ChangeInfo changeInfo) {
394a29fe6d4967a704799dc83d35ba80e426e9512cfYigit Boyar        if (changeInfo.oldHolder != null) {
395a29fe6d4967a704799dc83d35ba80e426e9512cfYigit Boyar            endChangeAnimationIfNecessary(changeInfo, changeInfo.oldHolder);
396a29fe6d4967a704799dc83d35ba80e426e9512cfYigit Boyar        }
397a29fe6d4967a704799dc83d35ba80e426e9512cfYigit Boyar        if (changeInfo.newHolder != null) {
398a29fe6d4967a704799dc83d35ba80e426e9512cfYigit Boyar            endChangeAnimationIfNecessary(changeInfo, changeInfo.newHolder);
399a29fe6d4967a704799dc83d35ba80e426e9512cfYigit Boyar        }
400a29fe6d4967a704799dc83d35ba80e426e9512cfYigit Boyar    }
401a29fe6d4967a704799dc83d35ba80e426e9512cfYigit Boyar    private boolean endChangeAnimationIfNecessary(ChangeInfo changeInfo, ViewHolder item) {
402e321eb5c831282c92a28a483692d8520b766a0a5Chet Haase        boolean oldItem = false;
403a29fe6d4967a704799dc83d35ba80e426e9512cfYigit Boyar        if (changeInfo.newHolder == item) {
404a29fe6d4967a704799dc83d35ba80e426e9512cfYigit Boyar            changeInfo.newHolder = null;
405a29fe6d4967a704799dc83d35ba80e426e9512cfYigit Boyar        } else if (changeInfo.oldHolder == item) {
406a29fe6d4967a704799dc83d35ba80e426e9512cfYigit Boyar            changeInfo.oldHolder = null;
407e321eb5c831282c92a28a483692d8520b766a0a5Chet Haase            oldItem = true;
408a29fe6d4967a704799dc83d35ba80e426e9512cfYigit Boyar        } else {
409a29fe6d4967a704799dc83d35ba80e426e9512cfYigit Boyar            return false;
410a29fe6d4967a704799dc83d35ba80e426e9512cfYigit Boyar        }
411a29fe6d4967a704799dc83d35ba80e426e9512cfYigit Boyar        ViewCompat.setAlpha(item.itemView, 1);
412a29fe6d4967a704799dc83d35ba80e426e9512cfYigit Boyar        ViewCompat.setTranslationX(item.itemView, 0);
413a29fe6d4967a704799dc83d35ba80e426e9512cfYigit Boyar        ViewCompat.setTranslationY(item.itemView, 0);
414e321eb5c831282c92a28a483692d8520b766a0a5Chet Haase        dispatchChangeFinished(item, oldItem);
415a29fe6d4967a704799dc83d35ba80e426e9512cfYigit Boyar        return true;
416235114f0ea0ae165e74a478f39bfc586392c53aaChet Haase    }
417235114f0ea0ae165e74a478f39bfc586392c53aaChet Haase
418235114f0ea0ae165e74a478f39bfc586392c53aaChet Haase    @Override
419d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase    public void endAnimation(ViewHolder item) {
420d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        final View view = item.itemView;
421a29fe6d4967a704799dc83d35ba80e426e9512cfYigit Boyar        // this will trigger end callback which should set properties to their target values.
422d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        ViewCompat.animate(view).cancel();
423a29fe6d4967a704799dc83d35ba80e426e9512cfYigit Boyar        // TODO if some other animations are chained to end, how do we cancel them as well?
424235114f0ea0ae165e74a478f39bfc586392c53aaChet Haase        for (int i = mPendingMoves.size() - 1; i >= 0; i--) {
425235114f0ea0ae165e74a478f39bfc586392c53aaChet Haase            MoveInfo moveInfo = mPendingMoves.get(i);
426235114f0ea0ae165e74a478f39bfc586392c53aaChet Haase            if (moveInfo.holder == item) {
427235114f0ea0ae165e74a478f39bfc586392c53aaChet Haase                ViewCompat.setTranslationY(view, 0);
428235114f0ea0ae165e74a478f39bfc586392c53aaChet Haase                ViewCompat.setTranslationX(view, 0);
429235114f0ea0ae165e74a478f39bfc586392c53aaChet Haase                dispatchMoveFinished(item);
430235114f0ea0ae165e74a478f39bfc586392c53aaChet Haase                mPendingMoves.remove(item);
431235114f0ea0ae165e74a478f39bfc586392c53aaChet Haase            }
43293b78dd7cbfafbe669e124b38a8e3ccb38ad3079Dake Gu        }
433a29fe6d4967a704799dc83d35ba80e426e9512cfYigit Boyar        endChangeAnimation(mPendingChanges, item);
434a29fe6d4967a704799dc83d35ba80e426e9512cfYigit Boyar        if (mPendingRemovals.remove(item)) {
435a29fe6d4967a704799dc83d35ba80e426e9512cfYigit Boyar            ViewCompat.setAlpha(view, 1);
43693b78dd7cbfafbe669e124b38a8e3ccb38ad3079Dake Gu            dispatchRemoveFinished(item);
43793b78dd7cbfafbe669e124b38a8e3ccb38ad3079Dake Gu        }
438a29fe6d4967a704799dc83d35ba80e426e9512cfYigit Boyar        if (mPendingAdditions.remove(item)) {
43993b78dd7cbfafbe669e124b38a8e3ccb38ad3079Dake Gu            ViewCompat.setAlpha(view, 1);
44093b78dd7cbfafbe669e124b38a8e3ccb38ad3079Dake Gu            dispatchAddFinished(item);
441235114f0ea0ae165e74a478f39bfc586392c53aaChet Haase        }
442a29fe6d4967a704799dc83d35ba80e426e9512cfYigit Boyar
4430e0bfdb790fd9477e3531a1db92c3377057f83b7Chet Haase        for (int i = mChangesList.size() - 1; i >= 0; i--) {
4440e0bfdb790fd9477e3531a1db92c3377057f83b7Chet Haase            ArrayList<ChangeInfo> changes = mChangesList.get(i);
4450e0bfdb790fd9477e3531a1db92c3377057f83b7Chet Haase            endChangeAnimation(changes, item);
4460e0bfdb790fd9477e3531a1db92c3377057f83b7Chet Haase            if (changes.isEmpty()) {
4470e0bfdb790fd9477e3531a1db92c3377057f83b7Chet Haase                mChangesList.remove(changes);
448ec93520d243d3eb3c6cddeaea7908d1b869bf367Dake Gu            }
449ec93520d243d3eb3c6cddeaea7908d1b869bf367Dake Gu        }
4500e0bfdb790fd9477e3531a1db92c3377057f83b7Chet Haase        for (int i = mMovesList.size() - 1; i >= 0; i--) {
4510e0bfdb790fd9477e3531a1db92c3377057f83b7Chet Haase            ArrayList<MoveInfo> moves = mMovesList.get(i);
4520e0bfdb790fd9477e3531a1db92c3377057f83b7Chet Haase            for (int j = moves.size() - 1; j >= 0; j--) {
4530e0bfdb790fd9477e3531a1db92c3377057f83b7Chet Haase                MoveInfo moveInfo = moves.get(j);
4540e0bfdb790fd9477e3531a1db92c3377057f83b7Chet Haase                if (moveInfo.holder == item) {
4550e0bfdb790fd9477e3531a1db92c3377057f83b7Chet Haase                    ViewCompat.setTranslationY(view, 0);
4560e0bfdb790fd9477e3531a1db92c3377057f83b7Chet Haase                    ViewCompat.setTranslationX(view, 0);
4570e0bfdb790fd9477e3531a1db92c3377057f83b7Chet Haase                    dispatchMoveFinished(item);
4580e0bfdb790fd9477e3531a1db92c3377057f83b7Chet Haase                    moves.remove(j);
4590e0bfdb790fd9477e3531a1db92c3377057f83b7Chet Haase                    if (moves.isEmpty()) {
4600e0bfdb790fd9477e3531a1db92c3377057f83b7Chet Haase                        mMovesList.remove(moves);
4610e0bfdb790fd9477e3531a1db92c3377057f83b7Chet Haase                    }
4620e0bfdb790fd9477e3531a1db92c3377057f83b7Chet Haase                    break;
4630e0bfdb790fd9477e3531a1db92c3377057f83b7Chet Haase                }
4640e0bfdb790fd9477e3531a1db92c3377057f83b7Chet Haase            }
4650e0bfdb790fd9477e3531a1db92c3377057f83b7Chet Haase        }
4660e0bfdb790fd9477e3531a1db92c3377057f83b7Chet Haase        for (int i = mAdditionsList.size() - 1; i >= 0; i--) {
4670e0bfdb790fd9477e3531a1db92c3377057f83b7Chet Haase            ArrayList<ViewHolder> additions = mAdditionsList.get(i);
4680e0bfdb790fd9477e3531a1db92c3377057f83b7Chet Haase            if (additions.remove(item)) {
4690e0bfdb790fd9477e3531a1db92c3377057f83b7Chet Haase                ViewCompat.setAlpha(view, 1);
4700e0bfdb790fd9477e3531a1db92c3377057f83b7Chet Haase                dispatchAddFinished(item);
4710e0bfdb790fd9477e3531a1db92c3377057f83b7Chet Haase                if (additions.isEmpty()) {
4720e0bfdb790fd9477e3531a1db92c3377057f83b7Chet Haase                    mAdditionsList.remove(additions);
4730e0bfdb790fd9477e3531a1db92c3377057f83b7Chet Haase                }
4740e0bfdb790fd9477e3531a1db92c3377057f83b7Chet Haase            }
475ec93520d243d3eb3c6cddeaea7908d1b869bf367Dake Gu        }
476a29fe6d4967a704799dc83d35ba80e426e9512cfYigit Boyar
477a29fe6d4967a704799dc83d35ba80e426e9512cfYigit Boyar        // animations should be ended by the cancel above.
478a29fe6d4967a704799dc83d35ba80e426e9512cfYigit Boyar        if (mRemoveAnimations.remove(item) && DEBUG) {
479a29fe6d4967a704799dc83d35ba80e426e9512cfYigit Boyar            throw new IllegalStateException("after animation is cancelled, item should not be in "
480a29fe6d4967a704799dc83d35ba80e426e9512cfYigit Boyar                    + "mRemoveAnimations list");
481d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        }
482a29fe6d4967a704799dc83d35ba80e426e9512cfYigit Boyar
483a29fe6d4967a704799dc83d35ba80e426e9512cfYigit Boyar        if (mAddAnimations.remove(item) && DEBUG) {
484a29fe6d4967a704799dc83d35ba80e426e9512cfYigit Boyar            throw new IllegalStateException("after animation is cancelled, item should not be in "
485a29fe6d4967a704799dc83d35ba80e426e9512cfYigit Boyar                    + "mAddAnimations list");
486d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        }
487a29fe6d4967a704799dc83d35ba80e426e9512cfYigit Boyar
488a29fe6d4967a704799dc83d35ba80e426e9512cfYigit Boyar        if (mChangeAnimations.remove(item) && DEBUG) {
489a29fe6d4967a704799dc83d35ba80e426e9512cfYigit Boyar            throw new IllegalStateException("after animation is cancelled, item should not be in "
490a29fe6d4967a704799dc83d35ba80e426e9512cfYigit Boyar                    + "mChangeAnimations list");
491a29fe6d4967a704799dc83d35ba80e426e9512cfYigit Boyar        }
492a29fe6d4967a704799dc83d35ba80e426e9512cfYigit Boyar
493a29fe6d4967a704799dc83d35ba80e426e9512cfYigit Boyar        if (mMoveAnimations.remove(item) && DEBUG) {
494a29fe6d4967a704799dc83d35ba80e426e9512cfYigit Boyar            throw new IllegalStateException("after animation is cancelled, item should not be in "
495a29fe6d4967a704799dc83d35ba80e426e9512cfYigit Boyar                    + "mMoveAnimations list");
496235114f0ea0ae165e74a478f39bfc586392c53aaChet Haase        }
497d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        dispatchFinishedWhenDone();
498d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase    }
499d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase
500d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase    @Override
501d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase    public boolean isRunning() {
502e3d27c97eb0769997cd9d73baabffff70551efe0Yigit Boyar        return (!mPendingAdditions.isEmpty() ||
503047e1151b1ce6965f5578eac83ee1ac3cf524ba7Yigit Boyar                !mPendingChanges.isEmpty() ||
504047e1151b1ce6965f5578eac83ee1ac3cf524ba7Yigit Boyar                !mPendingMoves.isEmpty() ||
505047e1151b1ce6965f5578eac83ee1ac3cf524ba7Yigit Boyar                !mPendingRemovals.isEmpty() ||
506e3d27c97eb0769997cd9d73baabffff70551efe0Yigit Boyar                !mMoveAnimations.isEmpty() ||
507d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase                !mRemoveAnimations.isEmpty() ||
508d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase                !mAddAnimations.isEmpty() ||
509235114f0ea0ae165e74a478f39bfc586392c53aaChet Haase                !mChangeAnimations.isEmpty() ||
5100e0bfdb790fd9477e3531a1db92c3377057f83b7Chet Haase                !mMovesList.isEmpty() ||
5110e0bfdb790fd9477e3531a1db92c3377057f83b7Chet Haase                !mAdditionsList.isEmpty() ||
5120e0bfdb790fd9477e3531a1db92c3377057f83b7Chet Haase                !mChangesList.isEmpty());
513d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase    }
514d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase
515d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase    /**
516d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase     * Check the state of currently pending and running animations. If there are none
517d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase     * pending/running, call {@link #dispatchAnimationsFinished()} to notify any
518d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase     * listeners.
519d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase     */
520d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase    private void dispatchFinishedWhenDone() {
521d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        if (!isRunning()) {
522d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase            dispatchAnimationsFinished();
523d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        }
524d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase    }
525d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase
526d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase    @Override
527d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase    public void endAnimations() {
52893b78dd7cbfafbe669e124b38a8e3ccb38ad3079Dake Gu        int count = mPendingMoves.size();
52993b78dd7cbfafbe669e124b38a8e3ccb38ad3079Dake Gu        for (int i = count - 1; i >= 0; i--) {
53093b78dd7cbfafbe669e124b38a8e3ccb38ad3079Dake Gu            MoveInfo item = mPendingMoves.get(i);
53193b78dd7cbfafbe669e124b38a8e3ccb38ad3079Dake Gu            View view = item.holder.itemView;
53293b78dd7cbfafbe669e124b38a8e3ccb38ad3079Dake Gu            ViewCompat.setTranslationY(view, 0);
53393b78dd7cbfafbe669e124b38a8e3ccb38ad3079Dake Gu            ViewCompat.setTranslationX(view, 0);
53493b78dd7cbfafbe669e124b38a8e3ccb38ad3079Dake Gu            dispatchMoveFinished(item.holder);
535ec93520d243d3eb3c6cddeaea7908d1b869bf367Dake Gu            mPendingMoves.remove(i);
53693b78dd7cbfafbe669e124b38a8e3ccb38ad3079Dake Gu        }
53793b78dd7cbfafbe669e124b38a8e3ccb38ad3079Dake Gu        count = mPendingRemovals.size();
53893b78dd7cbfafbe669e124b38a8e3ccb38ad3079Dake Gu        for (int i = count - 1; i >= 0; i--) {
53993b78dd7cbfafbe669e124b38a8e3ccb38ad3079Dake Gu            ViewHolder item = mPendingRemovals.get(i);
54093b78dd7cbfafbe669e124b38a8e3ccb38ad3079Dake Gu            dispatchRemoveFinished(item);
541ec93520d243d3eb3c6cddeaea7908d1b869bf367Dake Gu            mPendingRemovals.remove(i);
54293b78dd7cbfafbe669e124b38a8e3ccb38ad3079Dake Gu        }
54393b78dd7cbfafbe669e124b38a8e3ccb38ad3079Dake Gu        count = mPendingAdditions.size();
54493b78dd7cbfafbe669e124b38a8e3ccb38ad3079Dake Gu        for (int i = count - 1; i >= 0; i--) {
54593b78dd7cbfafbe669e124b38a8e3ccb38ad3079Dake Gu            ViewHolder item = mPendingAdditions.get(i);
54693b78dd7cbfafbe669e124b38a8e3ccb38ad3079Dake Gu            View view = item.itemView;
54793b78dd7cbfafbe669e124b38a8e3ccb38ad3079Dake Gu            ViewCompat.setAlpha(view, 1);
54893b78dd7cbfafbe669e124b38a8e3ccb38ad3079Dake Gu            dispatchAddFinished(item);
549ec93520d243d3eb3c6cddeaea7908d1b869bf367Dake Gu            mPendingAdditions.remove(i);
55093b78dd7cbfafbe669e124b38a8e3ccb38ad3079Dake Gu        }
551235114f0ea0ae165e74a478f39bfc586392c53aaChet Haase        count = mPendingChanges.size();
552235114f0ea0ae165e74a478f39bfc586392c53aaChet Haase        for (int i = count - 1; i >= 0; i--) {
553a29fe6d4967a704799dc83d35ba80e426e9512cfYigit Boyar            endChangeAnimationIfNecessary(mPendingChanges.get(i));
554235114f0ea0ae165e74a478f39bfc586392c53aaChet Haase        }
555a29fe6d4967a704799dc83d35ba80e426e9512cfYigit Boyar        mPendingChanges.clear();
556d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        if (!isRunning()) {
557d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase            return;
558d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        }
559235114f0ea0ae165e74a478f39bfc586392c53aaChet Haase
5600e0bfdb790fd9477e3531a1db92c3377057f83b7Chet Haase        int listCount = mMovesList.size();
5610e0bfdb790fd9477e3531a1db92c3377057f83b7Chet Haase        for (int i = listCount - 1; i >= 0; i--) {
5620e0bfdb790fd9477e3531a1db92c3377057f83b7Chet Haase            ArrayList<MoveInfo> moves = mMovesList.get(i);
5630e0bfdb790fd9477e3531a1db92c3377057f83b7Chet Haase            count = moves.size();
5640e0bfdb790fd9477e3531a1db92c3377057f83b7Chet Haase            for (int j = count - 1; j >= 0; j--) {
5650e0bfdb790fd9477e3531a1db92c3377057f83b7Chet Haase                MoveInfo moveInfo = moves.get(j);
5660e0bfdb790fd9477e3531a1db92c3377057f83b7Chet Haase                ViewHolder item = moveInfo.holder;
5670e0bfdb790fd9477e3531a1db92c3377057f83b7Chet Haase                View view = item.itemView;
5680e0bfdb790fd9477e3531a1db92c3377057f83b7Chet Haase                ViewCompat.setTranslationY(view, 0);
5690e0bfdb790fd9477e3531a1db92c3377057f83b7Chet Haase                ViewCompat.setTranslationX(view, 0);
5700e0bfdb790fd9477e3531a1db92c3377057f83b7Chet Haase                dispatchMoveFinished(moveInfo.holder);
5710e0bfdb790fd9477e3531a1db92c3377057f83b7Chet Haase                moves.remove(j);
5720e0bfdb790fd9477e3531a1db92c3377057f83b7Chet Haase                if (moves.isEmpty()) {
5730e0bfdb790fd9477e3531a1db92c3377057f83b7Chet Haase                    mMovesList.remove(moves);
5740e0bfdb790fd9477e3531a1db92c3377057f83b7Chet Haase                }
5750e0bfdb790fd9477e3531a1db92c3377057f83b7Chet Haase            }
576235114f0ea0ae165e74a478f39bfc586392c53aaChet Haase        }
5770e0bfdb790fd9477e3531a1db92c3377057f83b7Chet Haase        listCount = mAdditionsList.size();
5780e0bfdb790fd9477e3531a1db92c3377057f83b7Chet Haase        for (int i = listCount - 1; i >= 0; i--) {
5790e0bfdb790fd9477e3531a1db92c3377057f83b7Chet Haase            ArrayList<ViewHolder> additions = mAdditionsList.get(i);
5800e0bfdb790fd9477e3531a1db92c3377057f83b7Chet Haase            count = additions.size();
5810e0bfdb790fd9477e3531a1db92c3377057f83b7Chet Haase            for (int j = count - 1; j >= 0; j--) {
5820e0bfdb790fd9477e3531a1db92c3377057f83b7Chet Haase                ViewHolder item = additions.get(j);
5830e0bfdb790fd9477e3531a1db92c3377057f83b7Chet Haase                View view = item.itemView;
5840e0bfdb790fd9477e3531a1db92c3377057f83b7Chet Haase                ViewCompat.setAlpha(view, 1);
5850e0bfdb790fd9477e3531a1db92c3377057f83b7Chet Haase                dispatchAddFinished(item);
5860e0bfdb790fd9477e3531a1db92c3377057f83b7Chet Haase                additions.remove(j);
5870e0bfdb790fd9477e3531a1db92c3377057f83b7Chet Haase                if (additions.isEmpty()) {
5880e0bfdb790fd9477e3531a1db92c3377057f83b7Chet Haase                    mAdditionsList.remove(additions);
5890e0bfdb790fd9477e3531a1db92c3377057f83b7Chet Haase                }
5900e0bfdb790fd9477e3531a1db92c3377057f83b7Chet Haase            }
591235114f0ea0ae165e74a478f39bfc586392c53aaChet Haase        }
5920e0bfdb790fd9477e3531a1db92c3377057f83b7Chet Haase        listCount = mChangesList.size();
5930e0bfdb790fd9477e3531a1db92c3377057f83b7Chet Haase        for (int i = listCount - 1; i >= 0; i--) {
5940e0bfdb790fd9477e3531a1db92c3377057f83b7Chet Haase            ArrayList<ChangeInfo> changes = mChangesList.get(i);
5950e0bfdb790fd9477e3531a1db92c3377057f83b7Chet Haase            count = changes.size();
5960e0bfdb790fd9477e3531a1db92c3377057f83b7Chet Haase            for (int j = count - 1; j >= 0; j--) {
5970e0bfdb790fd9477e3531a1db92c3377057f83b7Chet Haase                endChangeAnimationIfNecessary(changes.get(j));
5980e0bfdb790fd9477e3531a1db92c3377057f83b7Chet Haase                if (changes.isEmpty()) {
5990e0bfdb790fd9477e3531a1db92c3377057f83b7Chet Haase                    mChangesList.remove(changes);
6000e0bfdb790fd9477e3531a1db92c3377057f83b7Chet Haase                }
6010e0bfdb790fd9477e3531a1db92c3377057f83b7Chet Haase            }
602235114f0ea0ae165e74a478f39bfc586392c53aaChet Haase        }
603235114f0ea0ae165e74a478f39bfc586392c53aaChet Haase
604a29fe6d4967a704799dc83d35ba80e426e9512cfYigit Boyar        cancelAll(mRemoveAnimations);
605a29fe6d4967a704799dc83d35ba80e426e9512cfYigit Boyar        cancelAll(mMoveAnimations);
606a29fe6d4967a704799dc83d35ba80e426e9512cfYigit Boyar        cancelAll(mAddAnimations);
607a29fe6d4967a704799dc83d35ba80e426e9512cfYigit Boyar        cancelAll(mChangeAnimations);
608ec93520d243d3eb3c6cddeaea7908d1b869bf367Dake Gu
609d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        dispatchAnimationsFinished();
610d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase    }
611d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase
612a29fe6d4967a704799dc83d35ba80e426e9512cfYigit Boyar    void cancelAll(List<ViewHolder> viewHolders) {
613a29fe6d4967a704799dc83d35ba80e426e9512cfYigit Boyar        for (int i = viewHolders.size() - 1; i >= 0; i--) {
614a29fe6d4967a704799dc83d35ba80e426e9512cfYigit Boyar            ViewCompat.animate(viewHolders.get(i).itemView).cancel();
615a29fe6d4967a704799dc83d35ba80e426e9512cfYigit Boyar        }
616a29fe6d4967a704799dc83d35ba80e426e9512cfYigit Boyar    }
617a29fe6d4967a704799dc83d35ba80e426e9512cfYigit Boyar
618d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase    private static class VpaListenerAdapter implements ViewPropertyAnimatorListener {
619d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        @Override
620d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        public void onAnimationStart(View view) {}
621d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase
622d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        @Override
623d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        public void onAnimationEnd(View view) {}
624d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase
625d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        @Override
626d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase        public void onAnimationCancel(View view) {}
627d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase    };
628d7d27e9ebe5c7325e67e1a8af265378bd2056cadChet Haase}
629