我尝试根据这些sources
为 RecyclerView 编写自定义 ItemAnimator所以,我有BaseItemAnimator
public abstract class BaseItemAnimator extends RecyclerView.ItemAnimator {
protected List<RecyclerView.ViewHolder> pendingRemovals = new ArrayList<>();
protected List<RecyclerView.ViewHolder> pendingAdditions = new ArrayList<>();
protected List<MoveState> pendingMoves = new ArrayList<>();
protected List<RecyclerView.ViewHolder> pendingRunAdditions = new ArrayList<>();
protected List<MoveState> pendingRunMoves = new ArrayList<>();
protected List<RecyclerView.ViewHolder> removals = new ArrayList<>();
protected List<RecyclerView.ViewHolder> additions = new ArrayList<>();
protected List<RecyclerView.ViewHolder> moves = new ArrayList<>();
protected static class MoveState {
public RecyclerView.ViewHolder holder;
public int fromX, fromY, toX, toY;
/**
* Constructor
* @param holder ViewHolder
* @param fromX Start x-coordinate of view location
* @param fromY Start y-coordinate of view location
* @param toX End x-coordinate of view location
* @param toY End y-coordinate of view location
*/
public MoveState(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;
}
}
@Override
public void runPendingAnimations() {
final boolean isEmptyRemovals = pendingRemovals.isEmpty();
final boolean isEmptyAdditions = pendingAdditions.isEmpty();
final boolean isEmptyMoves = pendingMoves.isEmpty();
if(isEmptyRemovals && isEmptyAdditions && isEmptyMoves)
return; //Animation is not required
//Execute remove animations
for(RecyclerView.ViewHolder holder : pendingRemovals) {
executeRemoveAnimation(holder);
}
pendingRemovals.clear();
//Execute move animations
if(!isEmptyMoves) {
pendingRunMoves.addAll(pendingMoves);
pendingMoves.clear();
Runnable moveAnimationRunner = new Runnable() {
@Override
public void run() {
for(MoveState moveState : pendingRunMoves)
executeMoveAnimation(moveState);
pendingRunMoves.clear();
}
};
if(!isEmptyMoves) {
}
else {
moveAnimationRunner.run();
}
}
//Execute add animations
if(!isEmptyAdditions) {
pendingRunAdditions.addAll(pendingAdditions);
pendingAdditions.clear();
Runnable addAnimationRunner = new Runnable() {
@Override
public void run() {
for(RecyclerView.ViewHolder holder : pendingRunAdditions)
executeAddAnimation(holder);
pendingRunAdditions.clear();
}
};
if(!(isEmptyMoves || isEmptyRemovals)) {
}
else {
addAnimationRunner.run();
}
}
}
@Override
public boolean animateRemove(RecyclerView.ViewHolder holder) {
prepareRemoveAnimation(holder);
pendingRemovals.add(holder);
return true;
}
@Override
public boolean animateAdd(RecyclerView.ViewHolder holder) {
prepareAddAnimation(holder);
pendingAdditions.add(holder);
return true;
}
@Override
public boolean animateMove(RecyclerView.ViewHolder holder,
int fromX, int fromY, int toX, int toY) {
final View view = holder.itemView;
int dX = toX - fromX;
int dY = toY - fromY;
if (dX == 0 && dY == 0) {
dispatchMoveFinished(holder);
return false;
}
if (dX != 0) {
ViewCompat.setTranslationX(view, -dX);
}
if (dY != 0) {
ViewCompat.setTranslationY(view, -dY);
}
pendingMoves.add(new MoveState(holder, fromX, fromY, toX, toY));
return true;
}
@Override
public boolean animateChange(RecyclerView.ViewHolder oldHolder,
RecyclerView.ViewHolder newHolder,
int fromLeft, int fromTop,
int toLeft, int toTop) {
//TODO: Make change animation
return false;
}
private void resetTranslation(final View view) {
ViewCompat.setTranslationY(view, 0);
ViewCompat.setTranslationX(view, 0);
}
@Override
public void endAnimation(RecyclerView.ViewHolder item) {
final View view = item.itemView;
ViewCompat.animate(view).cancel();
if (pendingMoves.remove(item)) {
resetTranslation(view);
dispatchMoveFinished(item);
}
if (pendingRemovals.remove(item)) {
dispatchRemoveFinished(item);
}
if (pendingAdditions.remove(item)) {
ViewCompat.setAlpha(view, 1);
dispatchAddFinished(item);
}
if (moves.remove(item)) {
resetTranslation(view);
dispatchMoveFinished(item);
}
if (removals.remove(item)) {
ViewCompat.setAlpha(view, 1);
dispatchRemoveFinished(item);
}
if (additions.remove(item)) {
ViewCompat.setAlpha(view, 1);
dispatchAddFinished(item);
}
dispatchFinishedWhenDone();
}
@Override
public void endAnimations() {
int count = pendingMoves.size();
for (int i = count - 1; i >= 0; i--) {
MoveState item = pendingMoves.get(i);
View view = item.holder.itemView;
ViewCompat.animate(view).cancel();
resetTranslation(view);
dispatchMoveFinished(item.holder);
pendingMoves.remove(item);
}
count = pendingRemovals.size();
for (int i = count - 1; i >= 0; i--) {
RecyclerView.ViewHolder item = pendingRemovals.get(i);
dispatchRemoveFinished(item);
pendingRemovals.remove(item);
}
count = pendingAdditions.size();
for (int i = count - 1; i >= 0; i--) {
RecyclerView.ViewHolder item = pendingAdditions.get(i);
View view = item.itemView;
ViewCompat.setAlpha(view, 1);
dispatchAddFinished(item);
pendingAdditions.remove(item);
}
if (!isRunning()) {
return;
}
count = moves.size();
for (int i = count - 1; i >= 0; i--) {
RecyclerView.ViewHolder item = moves.get(i);
View view = item.itemView;
ViewCompat.animate(view).cancel();
resetTranslation(view);
dispatchMoveFinished(item);
moves.remove(item);
}
count = removals.size();
for (int i = count - 1; i >= 0; i--) {
RecyclerView.ViewHolder item = removals.get(i);
View view = item.itemView;
ViewCompat.animate(view).cancel();
ViewCompat.setAlpha(view, 1);
dispatchRemoveFinished(item);
removals.remove(item);
}
count = additions.size();
for (int i = count - 1; i >= 0; i--) {
RecyclerView.ViewHolder item = additions.get(i);
View view = item.itemView;
ViewCompat.animate(view).cancel();
ViewCompat.setAlpha(view, 1);
dispatchAddFinished(item);
additions.remove(item);
}
pendingRunMoves.clear();
pendingRunAdditions.clear();
dispatchAnimationsFinished();
}
@Override
public boolean isRunning() {
return !(moves.isEmpty()
&& removals.isEmpty()
&& additions.isEmpty()
&& pendingRunMoves.isEmpty()
&& pendingRunAdditions.isEmpty());
}
protected abstract void prepareAddAnimation(RecyclerView.ViewHolder holder);
protected abstract void prepareRemoveAnimation(RecyclerView.ViewHolder holder);
protected abstract void executeAddAnimation(RecyclerView.ViewHolder holder);
protected abstract void executeRemoveAnimation(RecyclerView.ViewHolder holder);
protected void executeMoveAnimation(final MoveState moveState) {
final View view = moveState.holder.itemView;
final int dX = moveState.toX - moveState.fromX;
final int dY = moveState.toY - moveState.fromY;
ViewCompat.animate(view).cancel();
if (dX != 0) {
ViewCompat.animate(view).translationX(0);
}
if (dY != 0) {
ViewCompat.animate(view).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.
ViewCompat.animate(view)
.setDuration(getMoveDuration())
.setListener(new DefaultVPAListener() {
@Override
public void onAnimationCancel(View view) {
if (dX != 0) {
ViewCompat.setTranslationX(view, 0);
}
if (dY != 0) {
ViewCompat.setTranslationY(view, 0);
}
}
@Override
public void onAnimationEnd(View view) {
dispatchMoveFinished(moveState.holder);
moves.remove(moveState.holder);
dispatchFinishedWhenDone();
}
}).start();
moves.add(moveState.holder);
}
/**
* 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();
}
}
public static class DefaultVPAListener implements ViewPropertyAnimatorListener {
@Override
public void onAnimationStart(View view) {
}
@Override
public void onAnimationEnd(View view) {
}
@Override
public void onAnimationCancel(View view) {
}
}
}
和ColorSlideItemAnimator
public class ColorSlideItemAnimator extends BaseItemAnimator {
protected RecyclerView recyclerView;
public ColorSlideItemAnimator(RecyclerView recyclerView) {
this.recyclerView = recyclerView;
}
@Override
protected void prepareAddAnimation(final RecyclerView.ViewHolder holder) {
ViewCompat.setTranslationX(holder.itemView, -recyclerView.getWidth());
}
@Override
protected void prepareRemoveAnimation(RecyclerView.ViewHolder holder) {
}
@Override
protected void executeAddAnimation(final RecyclerView.ViewHolder holder) {
final View view = holder.itemView;
ViewCompat.animate(view).cancel();
ViewCompat.animate(view)
.translationX(0)
.setDuration(getAddDuration())
.setListener(new DefaultVPAListener() {
@Override
public void onAnimationCancel(View view) {
ViewCompat.setTranslationX(view, 0);
}
@Override
public void onAnimationEnd(View view) {
dispatchAddFinished(holder);
additions.remove(holder);
dispatchFinishedWhenDone();
}
}).start();
additions.add(holder);
}
@Override
protected void executeRemoveAnimation(final RecyclerView.ViewHolder holder) {
final View view = holder.itemView;
ViewCompat.animate(view).cancel();
ViewCompat.animate(view)
.setDuration(getRemoveDuration())
.translationX(-recyclerView.getWidth())
.setListener(new DefaultVPAListener() {
@Override
public void onAnimationEnd(View view) {
ViewCompat.setTranslationX(view, -recyclerView.getWidth());
dispatchRemoveFinished(holder);
removals.remove(holder);
dispatchFinishedWhenDone();
}
}).start();
removals.add(holder);
}
}
我编写此代码以了解git上的源代码,我可以编写需要我的动画师。这个代码有效,它是删除事件的幻灯片项目,但我无法理解当项目删除时如何折叠空间?
现在,项目滑动后我有空格。
P.S。我很抱歉我的英语。如果某些事情不可理解,我会尝试解释更多细节。