NekoX/TMessagesProj/src/main/java/androidx/recyclerview/widget/DefaultItemAnimator.java

746 lines
29 KiB
Java
Raw Normal View History

/*
2019-05-14 14:08:05 +02:00
* Copyright 2018 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
2019-05-14 14:08:05 +02:00
package androidx.recyclerview.widget;
2018-07-30 04:07:02 +02:00
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.TimeInterpolator;
import android.animation.ValueAnimator;
2020-04-24 11:21:58 +02:00
import android.os.Build;
import android.view.View;
2018-07-30 04:07:02 +02:00
import android.view.ViewPropertyAnimator;
import android.view.animation.Interpolator;
2019-05-14 14:08:05 +02:00
import androidx.annotation.NonNull;
import androidx.core.view.ViewCompat;
import org.telegram.messenger.BuildVars;
import java.util.ArrayList;
import java.util.List;
/**
* This implementation of {@link RecyclerView.ItemAnimator} provides basic
* animations on remove, add, and move events that happen to the items in
* a RecyclerView. RecyclerView uses a DefaultItemAnimator by default.
*
* @see RecyclerView#setItemAnimator(RecyclerView.ItemAnimator)
*/
2016-03-16 13:26:32 +01:00
public class DefaultItemAnimator extends SimpleItemAnimator {
private static final boolean DEBUG = BuildVars.DEBUG_VERSION;
2018-07-30 04:07:02 +02:00
private static TimeInterpolator sDefaultInterpolator;
protected Interpolator translationInterpolator;
2018-07-30 04:07:02 +02:00
protected ArrayList<RecyclerView.ViewHolder> mPendingRemovals = new ArrayList<>();
protected ArrayList<RecyclerView.ViewHolder> mPendingAdditions = new ArrayList<>();
protected ArrayList<MoveInfo> mPendingMoves = new ArrayList<>();
protected ArrayList<ChangeInfo> mPendingChanges = new ArrayList<>();
2019-05-14 14:08:05 +02:00
ArrayList<ArrayList<RecyclerView.ViewHolder>> mAdditionsList = new ArrayList<>();
2017-03-31 01:58:05 +02:00
ArrayList<ArrayList<MoveInfo>> mMovesList = new ArrayList<>();
ArrayList<ArrayList<ChangeInfo>> mChangesList = new ArrayList<>();
2021-03-19 11:25:58 +01:00
ArrayList<MoveInfo> currentMoves = new ArrayList<>();
ArrayList<ChangeInfo> currentChanges = new ArrayList<>();
2020-09-30 15:48:47 +02:00
protected ArrayList<RecyclerView.ViewHolder> mAddAnimations = new ArrayList<>();
protected ArrayList<RecyclerView.ViewHolder> mMoveAnimations = new ArrayList<>();
protected ArrayList<RecyclerView.ViewHolder> mRemoveAnimations = new ArrayList<>();
2019-05-14 14:08:05 +02:00
ArrayList<RecyclerView.ViewHolder> mChangeAnimations = new ArrayList<>();
protected boolean delayAnimations = true;
2018-07-30 04:07:02 +02:00
protected static class MoveInfo {
2019-05-14 14:08:05 +02:00
public RecyclerView.ViewHolder holder;
public int fromX, fromY, toX, toY;
2020-12-23 08:48:30 +01:00
public MoveInfo(RecyclerView.ViewHolder holder, int fromX, int fromY, int toX, int toY) {
this.holder = holder;
this.fromX = fromX;
this.fromY = fromY;
this.toX = toX;
this.toY = toY;
}
}
protected static class ChangeInfo {
2019-05-14 14:08:05 +02:00
public RecyclerView.ViewHolder oldHolder, newHolder;
public int fromX, fromY, toX, toY;
2019-05-14 14:08:05 +02:00
private ChangeInfo(RecyclerView.ViewHolder oldHolder, RecyclerView.ViewHolder newHolder) {
this.oldHolder = oldHolder;
this.newHolder = newHolder;
}
2019-05-14 14:08:05 +02:00
ChangeInfo(RecyclerView.ViewHolder oldHolder, RecyclerView.ViewHolder newHolder,
int fromX, int fromY, int toX, int toY) {
this(oldHolder, newHolder);
this.fromX = fromX;
this.fromY = fromY;
this.toX = toX;
this.toY = toY;
}
@Override
public String toString() {
2018-07-30 04:07:02 +02:00
return "ChangeInfo{"
+ "oldHolder=" + oldHolder
+ ", newHolder=" + newHolder
+ ", fromX=" + fromX
+ ", fromY=" + fromY
+ ", toX=" + toX
+ ", toY=" + toY
+ '}';
}
}
@Override
public void runPendingAnimations() {
boolean removalsPending = !mPendingRemovals.isEmpty();
boolean movesPending = !mPendingMoves.isEmpty();
boolean changesPending = !mPendingChanges.isEmpty();
boolean additionsPending = !mPendingAdditions.isEmpty();
if (!removalsPending && !movesPending && !additionsPending && !changesPending) {
// nothing to animate
return;
}
// First, remove stuff
2019-05-14 14:08:05 +02:00
for (RecyclerView.ViewHolder holder : mPendingRemovals) {
animateRemoveImpl(holder);
}
mPendingRemovals.clear();
// Next, move stuff
if (movesPending) {
2019-05-14 14:08:05 +02:00
final ArrayList<MoveInfo> moves = new ArrayList<>();
moves.addAll(mPendingMoves);
mMovesList.add(moves);
mPendingMoves.clear();
Runnable mover = new Runnable() {
@Override
public void run() {
for (MoveInfo moveInfo : moves) {
animateMoveImpl(moveInfo.holder, moveInfo);
2021-03-19 11:25:58 +01:00
currentMoves.add(moveInfo);
}
moves.clear();
mMovesList.remove(moves);
}
};
2018-07-30 04:07:02 +02:00
if (delayAnimations && removalsPending) {
View view = moves.get(0).holder.itemView;
ViewCompat.postOnAnimationDelayed(view, mover, getMoveAnimationDelay());
} else {
mover.run();
}
}
// Next, change stuff, to run in parallel with move animations
if (changesPending) {
2019-05-14 14:08:05 +02:00
final ArrayList<ChangeInfo> changes = new ArrayList<>();
changes.addAll(mPendingChanges);
mChangesList.add(changes);
mPendingChanges.clear();
Runnable changer = new Runnable() {
@Override
public void run() {
for (ChangeInfo change : changes) {
animateChangeImpl(change);
2021-03-19 11:25:58 +01:00
currentChanges.add(change);
}
changes.clear();
mChangesList.remove(changes);
}
};
2018-07-30 04:07:02 +02:00
if (delayAnimations && removalsPending) {
2019-05-14 14:08:05 +02:00
RecyclerView.ViewHolder holder = changes.get(0).oldHolder;
ViewCompat.postOnAnimationDelayed(holder.itemView, changer, getRemoveDuration());
} else {
changer.run();
}
}
// Next, add stuff
if (additionsPending) {
2019-05-14 14:08:05 +02:00
final ArrayList<RecyclerView.ViewHolder> additions = new ArrayList<>();
additions.addAll(mPendingAdditions);
mAdditionsList.add(additions);
mPendingAdditions.clear();
Runnable adder = new Runnable() {
2017-03-31 01:58:05 +02:00
@Override
public void run() {
2019-05-14 14:08:05 +02:00
for (RecyclerView.ViewHolder holder : additions) {
animateAddImpl(holder);
}
additions.clear();
mAdditionsList.remove(additions);
}
};
2018-07-30 04:07:02 +02:00
if (delayAnimations && (removalsPending || movesPending || changesPending)) {
long removeDuration = removalsPending ? getRemoveDuration() : 0;
long moveDuration = movesPending ? getMoveDuration() : 0;
long changeDuration = changesPending ? getChangeDuration() : 0;
2020-09-30 15:48:47 +02:00
long totalDelay = getAddAnimationDelay(removeDuration, moveDuration, changeDuration);
View view = additions.get(0).itemView;
ViewCompat.postOnAnimationDelayed(view, adder, totalDelay);
} else {
adder.run();
}
}
}
2020-07-26 10:03:38 +02:00
protected long getAddAnimationDelay(long removeDuration, long moveDuration, long changeDuration) {
return removeDuration + Math.max(moveDuration, changeDuration);
}
protected long getMoveAnimationDelay() {
return getRemoveDuration();
}
@Override
public boolean animateRemove(final RecyclerView.ViewHolder holder, ItemHolderInfo info) {
2015-09-24 22:52:02 +02:00
resetAnimation(holder);
mPendingRemovals.add(holder);
2022-01-10 03:27:47 +01:00
checkIsRunning();
return true;
}
2021-01-30 20:47:24 +01:00
2018-07-30 04:07:02 +02:00
public void setDelayAnimations(boolean value) {
delayAnimations = value;
}
protected void animateRemoveImpl(final RecyclerView.ViewHolder holder) {
final View view = holder.itemView;
2018-07-30 04:07:02 +02:00
final ViewPropertyAnimator animation = view.animate();
mRemoveAnimations.add(holder);
2018-07-30 04:07:02 +02:00
animation.setDuration(getRemoveDuration()).alpha(0).setListener(
new AnimatorListenerAdapter() {
@Override
public void onAnimationStart(Animator animator) {
dispatchRemoveStarting(holder);
}
2018-07-30 04:07:02 +02:00
@Override
public void onAnimationEnd(Animator animator) {
animation.setListener(null);
view.setAlpha(1);
view.setTranslationX(0);
view.setTranslationY(0);
2018-07-30 04:07:02 +02:00
dispatchRemoveFinished(holder);
mRemoveAnimations.remove(holder);
dispatchFinishedWhenDone();
}
}).start();
}
@Override
2019-05-14 14:08:05 +02:00
public boolean animateAdd(final RecyclerView.ViewHolder holder) {
2015-09-24 22:52:02 +02:00
resetAnimation(holder);
2018-07-30 04:07:02 +02:00
holder.itemView.setAlpha(0);
mPendingAdditions.add(holder);
2022-01-10 03:27:47 +01:00
checkIsRunning();
return true;
}
public void animateAddImpl(final RecyclerView.ViewHolder holder) {
final View view = holder.itemView;
2018-07-30 04:07:02 +02:00
final ViewPropertyAnimator animation = view.animate();
mAddAnimations.add(holder);
2018-07-30 04:07:02 +02:00
animation.alpha(1).setDuration(getAddDuration())
.setListener(new AnimatorListenerAdapter() {
@Override
2018-07-30 04:07:02 +02:00
public void onAnimationStart(Animator animator) {
dispatchAddStarting(holder);
}
2018-07-30 04:07:02 +02:00
@Override
2018-07-30 04:07:02 +02:00
public void onAnimationCancel(Animator animator) {
view.setAlpha(1);
}
@Override
2018-07-30 04:07:02 +02:00
public void onAnimationEnd(Animator animator) {
animation.setListener(null);
dispatchAddFinished(holder);
mAddAnimations.remove(holder);
dispatchFinishedWhenDone();
}
}).start();
}
@Override
public boolean animateMove(final RecyclerView.ViewHolder holder, ItemHolderInfo info, int fromX, int fromY,
int toX, int toY) {
final View view = holder.itemView;
2018-07-30 04:07:02 +02:00
fromX += (int) holder.itemView.getTranslationX();
fromY += (int) holder.itemView.getTranslationY();
2015-09-24 22:52:02 +02:00
resetAnimation(holder);
int deltaX = toX - fromX;
int deltaY = toY - fromY;
if (deltaX == 0 && deltaY == 0) {
dispatchMoveFinished(holder);
return false;
}
if (deltaX != 0) {
2018-07-30 04:07:02 +02:00
view.setTranslationX(-deltaX);
}
if (deltaY != 0) {
2018-07-30 04:07:02 +02:00
view.setTranslationY(-deltaY);
}
mPendingMoves.add(new MoveInfo(holder, fromX, fromY, toX, toY));
2022-01-10 03:27:47 +01:00
checkIsRunning();
return true;
}
2020-04-24 11:21:58 +02:00
protected void onMoveAnimationUpdate(RecyclerView.ViewHolder holder) {
}
2020-12-23 08:48:30 +01:00
protected void animateMoveImpl(final RecyclerView.ViewHolder holder, MoveInfo moveInfo) {
int fromX = moveInfo.fromX;
int fromY = moveInfo.fromY;
int toX = moveInfo.toX;
int toY = moveInfo.toY;
final View view = holder.itemView;
final int deltaX = toX - fromX;
final int deltaY = toY - fromY;
if (deltaX != 0) {
2018-07-30 04:07:02 +02:00
view.animate().translationX(0);
}
if (deltaY != 0) {
2018-07-30 04:07:02 +02:00
view.animate().translationY(0);
}
// TODO: make EndActions end listeners instead, since end actions aren't called when
// vpas are canceled (and can't end them. why?)
// need listener functionality in VPACompat for this. Ick.
2018-07-30 04:07:02 +02:00
final ViewPropertyAnimator animation = view.animate();
mMoveAnimations.add(holder);
2020-04-24 11:21:58 +02:00
if (Build.VERSION.SDK_INT >= 19) {
animation.setUpdateListener(animation1 -> onMoveAnimationUpdate(holder));
}
if (translationInterpolator != null) {
animation.setInterpolator(translationInterpolator);
}
2018-07-30 04:07:02 +02:00
animation.setDuration(getMoveDuration()).setListener(new AnimatorListenerAdapter() {
@Override
2018-07-30 04:07:02 +02:00
public void onAnimationStart(Animator animator) {
dispatchMoveStarting(holder);
}
2018-07-30 04:07:02 +02:00
@Override
2018-07-30 04:07:02 +02:00
public void onAnimationCancel(Animator animator) {
if (deltaX != 0) {
2018-07-30 04:07:02 +02:00
view.setTranslationX(0);
}
if (deltaY != 0) {
2018-07-30 04:07:02 +02:00
view.setTranslationY(0);
}
}
2018-07-30 04:07:02 +02:00
@Override
2018-07-30 04:07:02 +02:00
public void onAnimationEnd(Animator animator) {
animation.setListener(null);
dispatchMoveFinished(holder);
mMoveAnimations.remove(holder);
dispatchFinishedWhenDone();
}
}).start();
}
@Override
public boolean animateChange(RecyclerView.ViewHolder oldHolder, RecyclerView.ViewHolder newHolder, ItemHolderInfo info,
int fromX, int fromY, int toX, int toY) {
2016-03-16 13:26:32 +01:00
if (oldHolder == newHolder) {
// Don't know how to run change animations when the same view holder is re-used.
// run a move animation to handle position changes.
return animateMove(oldHolder,info, fromX, fromY, toX, toY);
2016-03-16 13:26:32 +01:00
}
2018-07-30 04:07:02 +02:00
final float prevTranslationX = oldHolder.itemView.getTranslationX();
final float prevTranslationY = oldHolder.itemView.getTranslationY();
final float prevAlpha = oldHolder.itemView.getAlpha();
2015-09-24 22:52:02 +02:00
resetAnimation(oldHolder);
int deltaX = (int) (toX - fromX - prevTranslationX);
int deltaY = (int) (toY - fromY - prevTranslationY);
// recover prev translation state after ending animation
2018-07-30 04:07:02 +02:00
oldHolder.itemView.setTranslationX(prevTranslationX);
oldHolder.itemView.setTranslationY(prevTranslationY);
oldHolder.itemView.setAlpha(prevAlpha);
2016-03-16 13:26:32 +01:00
if (newHolder != null) {
// carry over translation values
2015-09-24 22:52:02 +02:00
resetAnimation(newHolder);
2018-07-30 04:07:02 +02:00
newHolder.itemView.setTranslationX(-deltaX);
newHolder.itemView.setTranslationY(-deltaY);
newHolder.itemView.setAlpha(0);
}
mPendingChanges.add(new ChangeInfo(oldHolder, newHolder, fromX, fromY, toX, toY));
2022-01-10 03:27:47 +01:00
checkIsRunning();
return true;
}
2017-03-31 01:58:05 +02:00
void animateChangeImpl(final ChangeInfo changeInfo) {
2019-05-14 14:08:05 +02:00
final RecyclerView.ViewHolder holder = changeInfo.oldHolder;
final View view = holder == null ? null : holder.itemView;
2019-05-14 14:08:05 +02:00
final RecyclerView.ViewHolder newHolder = changeInfo.newHolder;
final View newView = newHolder != null ? newHolder.itemView : null;
if (view != null) {
2018-07-30 04:07:02 +02:00
final ViewPropertyAnimator oldViewAnim = view.animate().setDuration(
getChangeDuration());
mChangeAnimations.add(changeInfo.oldHolder);
oldViewAnim.translationX(changeInfo.toX - changeInfo.fromX);
oldViewAnim.translationY(changeInfo.toY - changeInfo.fromY);
2018-07-30 04:07:02 +02:00
oldViewAnim.alpha(0).setListener(new AnimatorListenerAdapter() {
@Override
2018-07-30 04:07:02 +02:00
public void onAnimationStart(Animator animator) {
dispatchChangeStarting(changeInfo.oldHolder, true);
}
@Override
2018-07-30 04:07:02 +02:00
public void onAnimationEnd(Animator animator) {
oldViewAnim.setListener(null);
2018-07-30 04:07:02 +02:00
view.setAlpha(1);
view.setTranslationX(0);
view.setTranslationY(0);
dispatchChangeFinished(changeInfo.oldHolder, true);
mChangeAnimations.remove(changeInfo.oldHolder);
dispatchFinishedWhenDone();
}
}).start();
}
if (newView != null) {
2018-07-30 04:07:02 +02:00
final ViewPropertyAnimator newViewAnimation = newView.animate();
mChangeAnimations.add(changeInfo.newHolder);
2018-07-30 04:07:02 +02:00
newViewAnimation.translationX(0).translationY(0).setDuration(getChangeDuration())
.alpha(1).setListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationStart(Animator animator) {
dispatchChangeStarting(changeInfo.newHolder, false);
}
@Override
public void onAnimationEnd(Animator animator) {
newViewAnimation.setListener(null);
newView.setAlpha(1);
newView.setTranslationX(0);
newView.setTranslationY(0);
dispatchChangeFinished(changeInfo.newHolder, false);
mChangeAnimations.remove(changeInfo.newHolder);
dispatchFinishedWhenDone();
}
}).start();
}
}
2019-05-14 14:08:05 +02:00
private void endChangeAnimation(List<ChangeInfo> infoList, RecyclerView.ViewHolder item) {
for (int i = infoList.size() - 1; i >= 0; i--) {
ChangeInfo changeInfo = infoList.get(i);
if (endChangeAnimationIfNecessary(changeInfo, item)) {
if (changeInfo.oldHolder == null && changeInfo.newHolder == null) {
infoList.remove(changeInfo);
}
}
}
}
protected void endChangeAnimationIfNecessary(ChangeInfo changeInfo) {
if (changeInfo.oldHolder != null) {
endChangeAnimationIfNecessary(changeInfo, changeInfo.oldHolder);
}
if (changeInfo.newHolder != null) {
endChangeAnimationIfNecessary(changeInfo, changeInfo.newHolder);
}
}
protected boolean endChangeAnimationIfNecessary(ChangeInfo changeInfo, RecyclerView.ViewHolder item) {
boolean oldItem = false;
if (changeInfo.newHolder == item) {
changeInfo.newHolder = null;
} else if (changeInfo.oldHolder == item) {
changeInfo.oldHolder = null;
oldItem = true;
} else {
return false;
}
2018-07-30 04:07:02 +02:00
item.itemView.setAlpha(1);
item.itemView.setTranslationX(0);
item.itemView.setTranslationY(0);
dispatchChangeFinished(item, oldItem);
return true;
}
@Override
2019-05-14 14:08:05 +02:00
public void endAnimation(RecyclerView.ViewHolder item) {
final View view = item.itemView;
// this will trigger end callback which should set properties to their target values.
2018-07-30 04:07:02 +02:00
view.animate().cancel();
// TODO if some other animations are chained to end, how do we cancel them as well?
for (int i = mPendingMoves.size() - 1; i >= 0; i--) {
MoveInfo moveInfo = mPendingMoves.get(i);
if (moveInfo.holder == item) {
2018-07-30 04:07:02 +02:00
view.setTranslationY(0);
view.setTranslationX(0);
dispatchMoveFinished(item);
mPendingMoves.remove(i);
}
}
endChangeAnimation(mPendingChanges, item);
if (mPendingRemovals.remove(item)) {
2018-07-30 04:07:02 +02:00
view.setAlpha(1);
2020-09-30 15:48:47 +02:00
view.setScaleX(1f);
view.setScaleY(1f);
dispatchRemoveFinished(item);
}
if (mPendingAdditions.remove(item)) {
2018-07-30 04:07:02 +02:00
view.setAlpha(1);
2020-09-30 15:48:47 +02:00
view.setScaleX(1f);
view.setScaleY(1f);
dispatchAddFinished(item);
}
for (int i = mChangesList.size() - 1; i >= 0; i--) {
ArrayList<ChangeInfo> changes = mChangesList.get(i);
endChangeAnimation(changes, item);
if (changes.isEmpty()) {
mChangesList.remove(i);
}
}
for (int i = mMovesList.size() - 1; i >= 0; i--) {
ArrayList<MoveInfo> moves = mMovesList.get(i);
for (int j = moves.size() - 1; j >= 0; j--) {
MoveInfo moveInfo = moves.get(j);
if (moveInfo.holder == item) {
2018-07-30 04:07:02 +02:00
view.setTranslationY(0);
view.setTranslationX(0);
dispatchMoveFinished(item);
moves.remove(j);
if (moves.isEmpty()) {
mMovesList.remove(i);
}
break;
}
}
}
for (int i = mAdditionsList.size() - 1; i >= 0; i--) {
2019-05-14 14:08:05 +02:00
ArrayList<RecyclerView.ViewHolder> additions = mAdditionsList.get(i);
if (additions.remove(item)) {
2018-07-30 04:07:02 +02:00
view.setAlpha(1);
dispatchAddFinished(item);
if (additions.isEmpty()) {
mAdditionsList.remove(i);
}
}
}
// animations should be ended by the cancel above.
2016-03-16 13:26:32 +01:00
//noinspection PointlessBooleanExpression,ConstantConditions
if (mRemoveAnimations.remove(item) && BuildVars.DEBUG_VERSION) {
throw new IllegalStateException("after animation is cancelled, item should not be in "
+ "mRemoveAnimations list");
}
2016-03-16 13:26:32 +01:00
//noinspection PointlessBooleanExpression,ConstantConditions
if (mAddAnimations.remove(item) && BuildVars.DEBUG_VERSION) {
throw new IllegalStateException("after animation is cancelled, item should not be in "
+ "mAddAnimations list");
}
2016-03-16 13:26:32 +01:00
//noinspection PointlessBooleanExpression,ConstantConditions
if (mChangeAnimations.remove(item) && BuildVars.DEBUG_VERSION) {
throw new IllegalStateException("after animation is cancelled, item should not be in "
+ "mChangeAnimations list");
}
2016-03-16 13:26:32 +01:00
//noinspection PointlessBooleanExpression,ConstantConditions
if (mMoveAnimations.remove(item) && BuildVars.DEBUG_VERSION) {
throw new IllegalStateException("after animation is cancelled, item should not be in "
+ "mMoveAnimations list");
}
dispatchFinishedWhenDone();
}
public void resetAnimation(RecyclerView.ViewHolder holder) {
2018-07-30 04:07:02 +02:00
if (sDefaultInterpolator == null) {
sDefaultInterpolator = new ValueAnimator().getInterpolator();
}
holder.itemView.animate().setInterpolator(sDefaultInterpolator);
2015-09-24 22:52:02 +02:00
endAnimation(holder);
}
2021-03-19 11:25:58 +01:00
public float getTargetY(View view) {
for (int i = currentMoves.size() - 1; i >= 0; i--) {
MoveInfo moveInfo = currentMoves.get(i);
if (moveInfo.holder.itemView == view) {
return Math.min(Math.min(moveInfo.toY, moveInfo.fromY), view.getY());
}
}
for (int i = currentChanges.size() - 1; i >= 0; i--) {
ChangeInfo changeInfo = currentChanges.get(i);
if (changeInfo.oldHolder.itemView == view || changeInfo.newHolder.itemView == view) {
return Math.min(Math.min(changeInfo.toY, changeInfo.fromY), view.getY());
}
}
return view.getY();
}
@Override
public boolean isRunning() {
2018-07-30 04:07:02 +02:00
return (!mPendingAdditions.isEmpty()
|| !mPendingChanges.isEmpty()
|| !mPendingMoves.isEmpty()
|| !mPendingRemovals.isEmpty()
|| !mMoveAnimations.isEmpty()
|| !mRemoveAnimations.isEmpty()
|| !mAddAnimations.isEmpty()
|| !mChangeAnimations.isEmpty()
|| !mMovesList.isEmpty()
|| !mAdditionsList.isEmpty()
|| !mChangesList.isEmpty());
}
/**
* Check the state of currently pending and running animations. If there are none
* pending/running, call {@link #dispatchAnimationsFinished()} to notify any
* listeners.
*/
protected void dispatchFinishedWhenDone() {
if (!isRunning()) {
dispatchAnimationsFinished();
2019-05-14 14:08:05 +02:00
onAllAnimationsDone();
2021-03-19 11:25:58 +01:00
currentMoves.clear();
currentChanges.clear();
}
}
2019-05-14 14:08:05 +02:00
protected void onAllAnimationsDone() {
}
@Override
public void endAnimations() {
int count = mPendingMoves.size();
for (int i = count - 1; i >= 0; i--) {
MoveInfo item = mPendingMoves.get(i);
View view = item.holder.itemView;
2018-07-30 04:07:02 +02:00
view.setTranslationY(0);
view.setTranslationX(0);
dispatchMoveFinished(item.holder);
mPendingMoves.remove(i);
}
count = mPendingRemovals.size();
for (int i = count - 1; i >= 0; i--) {
2019-05-14 14:08:05 +02:00
RecyclerView.ViewHolder item = mPendingRemovals.get(i);
dispatchRemoveFinished(item);
mPendingRemovals.remove(i);
}
count = mPendingAdditions.size();
for (int i = count - 1; i >= 0; i--) {
2019-05-14 14:08:05 +02:00
RecyclerView.ViewHolder item = mPendingAdditions.get(i);
2018-07-30 04:07:02 +02:00
item.itemView.setAlpha(1);
dispatchAddFinished(item);
mPendingAdditions.remove(i);
}
count = mPendingChanges.size();
for (int i = count - 1; i >= 0; i--) {
endChangeAnimationIfNecessary(mPendingChanges.get(i));
}
mPendingChanges.clear();
if (!isRunning()) {
return;
}
int listCount = mMovesList.size();
for (int i = listCount - 1; i >= 0; i--) {
ArrayList<MoveInfo> moves = mMovesList.get(i);
count = moves.size();
for (int j = count - 1; j >= 0; j--) {
MoveInfo moveInfo = moves.get(j);
2019-05-14 14:08:05 +02:00
RecyclerView.ViewHolder item = moveInfo.holder;
View view = item.itemView;
2018-07-30 04:07:02 +02:00
view.setTranslationY(0);
view.setTranslationX(0);
dispatchMoveFinished(moveInfo.holder);
moves.remove(j);
if (moves.isEmpty()) {
mMovesList.remove(moves);
}
}
}
listCount = mAdditionsList.size();
for (int i = listCount - 1; i >= 0; i--) {
2019-05-14 14:08:05 +02:00
ArrayList<RecyclerView.ViewHolder> additions = mAdditionsList.get(i);
count = additions.size();
for (int j = count - 1; j >= 0; j--) {
2019-05-14 14:08:05 +02:00
RecyclerView.ViewHolder item = additions.get(j);
View view = item.itemView;
2018-07-30 04:07:02 +02:00
view.setAlpha(1);
dispatchAddFinished(item);
additions.remove(j);
if (additions.isEmpty()) {
mAdditionsList.remove(additions);
}
}
}
listCount = mChangesList.size();
for (int i = listCount - 1; i >= 0; i--) {
ArrayList<ChangeInfo> changes = mChangesList.get(i);
count = changes.size();
for (int j = count - 1; j >= 0; j--) {
endChangeAnimationIfNecessary(changes.get(j));
if (changes.isEmpty()) {
mChangesList.remove(changes);
}
}
}
cancelAll(mRemoveAnimations);
cancelAll(mMoveAnimations);
cancelAll(mAddAnimations);
cancelAll(mChangeAnimations);
dispatchAnimationsFinished();
}
2019-05-14 14:08:05 +02:00
void cancelAll(List<RecyclerView.ViewHolder> viewHolders) {
for (int i = viewHolders.size() - 1; i >= 0; i--) {
2018-07-30 04:07:02 +02:00
viewHolders.get(i).itemView.animate().cancel();
}
}
2016-03-16 13:26:32 +01:00
/**
* {@inheritDoc}
* <p>
* If the payload list is not empty, DefaultItemAnimator returns <code>true</code>.
* When this is the case:
* <ul>
2019-05-14 14:08:05 +02:00
* <li>If you override {@link #animateChange(RecyclerView.ViewHolder, RecyclerView.ViewHolder, int, int, int, int)}, both
2016-03-16 13:26:32 +01:00
* ViewHolder arguments will be the same instance.
* </li>
* <li>
2019-05-14 14:08:05 +02:00
* If you are not overriding {@link #animateChange(RecyclerView.ViewHolder, RecyclerView.ViewHolder, int, int, int, int)},
* then DefaultItemAnimator will call {@link #animateMove(RecyclerView.ViewHolder, int, int, int, int)} and
2016-03-16 13:26:32 +01:00
* run a move animation instead.
* </li>
* </ul>
*/
@Override
2019-05-14 14:08:05 +02:00
public boolean canReuseUpdatedViewHolder(@NonNull RecyclerView.ViewHolder viewHolder,
2016-03-16 13:26:32 +01:00
@NonNull List<Object> payloads) {
return !payloads.isEmpty() || super.canReuseUpdatedViewHolder(viewHolder, payloads);
}
2021-06-25 02:43:10 +02:00
public void setTranslationInterpolator(Interpolator translationInterpolator) {
this.translationInterpolator = translationInterpolator;
}
2022-01-10 03:27:47 +01:00
public void checkIsRunning() {
}
}