Java tutorial
/* * Copyright 2015 Hippo Seven * * 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. */ package com.hippo.nimingban.itemanimator; import android.support.v4.animation.AnimatorCompatHelper; import android.support.v4.view.ViewCompat; import android.support.v4.view.ViewPropertyAnimatorCompat; import android.support.v4.view.ViewPropertyAnimatorListener; import android.support.v7.widget.RecyclerView; import android.view.View; import com.hippo.util.AnimationUtils2; import java.util.ArrayList; import java.util.List; public class FloatItemAnimator extends RecyclerView.ItemAnimator { private static final float SPEED = 5f; private ArrayList<RecyclerView.ViewHolder> mPendingAdditions = new ArrayList<>(); private ArrayList<ArrayList<RecyclerView.ViewHolder>> mAdditionsList = new ArrayList<>(); private ArrayList<RecyclerView.ViewHolder> mAddAnimations = new ArrayList<>(); private RecyclerView mRecyclerView; public FloatItemAnimator(RecyclerView recyclerView) { mRecyclerView = recyclerView; } @Override public void runPendingAnimations() { if (!mPendingAdditions.isEmpty()) { final ArrayList<RecyclerView.ViewHolder> additions = new ArrayList<>(); additions.addAll(mPendingAdditions); mAdditionsList.add(additions); mPendingAdditions.clear(); Runnable adder = new Runnable() { @Override public void run() { float translationY = 0; int height = mRecyclerView.getHeight(); for (RecyclerView.ViewHolder holder : additions) { final View view = holder.itemView; translationY = Math.max(translationY, height - view.getX()); } for (RecyclerView.ViewHolder holder : additions) { animateAddImpl(holder, translationY); } additions.clear(); mAdditionsList.remove(additions); } }; adder.run(); } } @Override public boolean animateRemove(final RecyclerView.ViewHolder holder) { return false; } @Override public boolean animateAdd(final RecyclerView.ViewHolder holder) { resetAnimation(holder); holder.itemView.setVisibility(View.INVISIBLE); mPendingAdditions.add(holder); return true; } private void animateAddImpl(final RecyclerView.ViewHolder holder, float translationY) { final View view = holder.itemView; final ViewPropertyAnimatorCompat animation = ViewCompat.animate(view); view.setVisibility(View.VISIBLE); mAddAnimations.add(holder); view.setTranslationY(translationY); animation.translationY(0.0f).setDuration((long) (translationY / SPEED)) .setInterpolator(AnimationUtils2.FAST_SLOW_INTERPOLATOR).setListener(new VpaListenerAdapter() { @Override public void onAnimationStart(View view) { dispatchAddStarting(holder); } @Override public void onAnimationCancel(View view) { ViewCompat.setAlpha(view, 1); } @Override public void onAnimationEnd(View view) { animation.setListener(null); dispatchAddFinished(holder); mAddAnimations.remove(holder); dispatchFinishedWhenDone(); } }).start(); } @Override public boolean animateMove(final RecyclerView.ViewHolder holder, int fromX, int fromY, int toX, int toY) { return false; } @Override public boolean animateChange(RecyclerView.ViewHolder oldHolder, RecyclerView.ViewHolder newHolder, int fromX, int fromY, int toX, int toY) { return false; } @Override public void endAnimation(RecyclerView.ViewHolder item) { final View view = item.itemView; // this will trigger end callback which should set properties to their target values. ViewCompat.animate(view).cancel(); if (mPendingAdditions.remove(item)) { ViewCompat.setAlpha(view, 1); dispatchAddFinished(item); } for (int i = mAdditionsList.size() - 1; i >= 0; i--) { ArrayList<RecyclerView.ViewHolder> additions = mAdditionsList.get(i); if (additions.remove(item)) { ViewCompat.setAlpha(view, 1); dispatchAddFinished(item); if (additions.isEmpty()) { mAdditionsList.remove(i); } } } dispatchFinishedWhenDone(); } private void resetAnimation(RecyclerView.ViewHolder holder) { AnimatorCompatHelper.clearInterpolator(holder.itemView); endAnimation(holder); } @Override public boolean isRunning() { return (!mPendingAdditions.isEmpty() || !mAddAnimations.isEmpty() || !mAdditionsList.isEmpty()); } /** * Check the state of currently pending and running animations. If there are none * pending/running, call {@link #dispatchAnimationsFinished()} to notify any * listeners. */ private void dispatchFinishedWhenDone() { if (!isRunning()) { dispatchAnimationsFinished(); } } @Override public void endAnimations() { int count = mPendingAdditions.size(); for (int i = count - 1; i >= 0; i--) { RecyclerView.ViewHolder item = mPendingAdditions.get(i); View view = item.itemView; ViewCompat.setAlpha(view, 1); dispatchAddFinished(item); mPendingAdditions.remove(i); } if (!isRunning()) { return; } int listCount = mAdditionsList.size(); for (int i = listCount - 1; i >= 0; i--) { ArrayList<RecyclerView.ViewHolder> additions = mAdditionsList.get(i); count = additions.size(); for (int j = count - 1; j >= 0; j--) { RecyclerView.ViewHolder item = additions.get(j); View view = item.itemView; ViewCompat.setAlpha(view, 1); dispatchAddFinished(item); additions.remove(j); if (additions.isEmpty()) { mAdditionsList.remove(additions); } } } cancelAll(mAddAnimations); dispatchAnimationsFinished(); } void cancelAll(List<RecyclerView.ViewHolder> viewHolders) { for (int i = viewHolders.size() - 1; i >= 0; i--) { ViewCompat.animate(viewHolders.get(i).itemView).cancel(); } } private static class VpaListenerAdapter implements ViewPropertyAnimatorListener { @Override public void onAnimationStart(View view) { } @Override public void onAnimationEnd(View view) { } @Override public void onAnimationCancel(View view) { } } }