diff --git a/animators/build.gradle b/animators/build.gradle index 48c92a1..d40114d 100644 --- a/animators/build.gradle +++ b/animators/build.gradle @@ -1,37 +1,43 @@ apply plugin: 'com.android.library' +apply plugin: 'kotlin-android' android { - compileSdkVersion COMPILE_SDK_VERSION as int + compileSdkVersion COMPILE_SDK_VERSION as int - defaultConfig { - minSdkVersion MIN_SDK_VERSION as int - targetSdkVersion TARGET_SDK_VERSION as int - } + defaultConfig { + minSdkVersion MIN_SDK_VERSION as int + targetSdkVersion TARGET_SDK_VERSION as int + } } dependencies { - implementation "androidx.recyclerview:recyclerview:1.0.0" + implementation "androidx.recyclerview:recyclerview:1.0.0" + implementation "androidx.core:core-ktx:1.3.0" + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" } ext { - bintrayRepo = 'maven' - bintrayName = 'recyclerview-animators' - bintrayUserOrg = 'wasabeef' - publishedGroupId = 'jp.wasabeef' - libraryName = 'recyclerview-animators' - artifact = 'recyclerview-animators' - libraryDescription = 'Which provides simple Item animations to RecyclerView items' - siteUrl = 'https://github.com/wasabeef/recyclerview-animators' - gitUrl = 'https://github.com/wasabeef/recyclerview-animators.git' - issueUrl = 'https://github.com/wasabeef/recyclerview-animators/issues' - libraryVersion = VERSION_NAME - developerId = 'wasabeef' - developerName = 'Wasabeef' - developerEmail = 'dadadada.chop@gmail.com' - licenseName = 'The Apache Software License, Version 2.0' - licenseUrl = 'http://www.apache.org/licenses/LICENSE-2.0.txt' - allLicenses = ["Apache-2.0"] + bintrayRepo = 'maven' + bintrayName = 'recyclerview-animators' + bintrayUserOrg = 'wasabeef' + publishedGroupId = 'jp.wasabeef' + libraryName = 'recyclerview-animators' + artifact = 'recyclerview-animators' + libraryDescription = 'Which provides simple Item animations to RecyclerView items' + siteUrl = 'https://github.com/wasabeef/recyclerview-animators' + gitUrl = 'https://github.com/wasabeef/recyclerview-animators.git' + issueUrl = 'https://github.com/wasabeef/recyclerview-animators/issues' + libraryVersion = VERSION_NAME + developerId = 'wasabeef' + developerName = 'Wasabeef' + developerEmail = 'dadadada.chop@gmail.com' + licenseName = 'The Apache Software License, Version 2.0' + licenseUrl = 'http://www.apache.org/licenses/LICENSE-2.0.txt' + allLicenses = ["Apache-2.0"] } apply from: 'https://gist.githubusercontent.com/wasabeef/cf14805bee509baf7461974582f17d26/raw/bintray-v1.gradle' -apply from: 'https://gist.githubusercontent.com/wasabeef/cf14805bee509baf7461974582f17d26/raw/install-v1.gradle' \ No newline at end of file +apply from: 'https://gist.githubusercontent.com/wasabeef/cf14805bee509baf7461974582f17d26/raw/install-v1.gradle' +repositories { + mavenCentral() +} \ No newline at end of file diff --git a/animators/src/main/java/jp/wasabeef/recyclerview/animators/BaseItemAnimator.java b/animators/src/main/java/jp/wasabeef/recyclerview/animators/BaseItemAnimator.java deleted file mode 100644 index 5d56737..0000000 --- a/animators/src/main/java/jp/wasabeef/recyclerview/animators/BaseItemAnimator.java +++ /dev/null @@ -1,713 +0,0 @@ -package jp.wasabeef.recyclerview.animators; -/* - * Copyright (C) 2018 Wasabeef - * Copyright (C) 2014 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. - * - */ - -import androidx.core.view.ViewCompat; -import androidx.core.view.ViewPropertyAnimatorCompat; -import androidx.core.view.ViewPropertyAnimatorListener; -import androidx.recyclerview.widget.RecyclerView; -import androidx.recyclerview.widget.RecyclerView.ViewHolder; -import androidx.recyclerview.widget.SimpleItemAnimator; -import android.view.View; -import android.view.animation.DecelerateInterpolator; -import android.view.animation.Interpolator; - -import java.util.ArrayList; -import java.util.List; - -import jp.wasabeef.recyclerview.animators.holder.AnimateViewHolder; -import jp.wasabeef.recyclerview.internal.ViewHelper; - -public abstract class BaseItemAnimator extends SimpleItemAnimator { - - private static final boolean DEBUG = false; - - private ArrayList mPendingRemovals = new ArrayList<>(); - private ArrayList mPendingAdditions = new ArrayList<>(); - private ArrayList mPendingMoves = new ArrayList<>(); - private ArrayList mPendingChanges = new ArrayList<>(); - - private ArrayList> mAdditionsList = new ArrayList<>(); - private ArrayList> mMovesList = new ArrayList<>(); - private ArrayList> mChangesList = new ArrayList<>(); - - protected ArrayList mAddAnimations = new ArrayList<>(); - private ArrayList mMoveAnimations = new ArrayList<>(); - protected ArrayList mRemoveAnimations = new ArrayList<>(); - private ArrayList mChangeAnimations = new ArrayList<>(); - - protected Interpolator mInterpolator = new DecelerateInterpolator(); - - private static class MoveInfo { - - public ViewHolder holder; - public int fromX, fromY, toX, toY; - - private MoveInfo(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; - } - } - - private static class ChangeInfo { - - public ViewHolder oldHolder, newHolder; - public int fromX, fromY, toX, toY; - - private ChangeInfo(ViewHolder oldHolder, ViewHolder newHolder) { - this.oldHolder = oldHolder; - this.newHolder = newHolder; - } - - private ChangeInfo(ViewHolder oldHolder, 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() { - return "ChangeInfo{" + - "oldHolder=" + oldHolder + - ", newHolder=" + newHolder + - ", fromX=" + fromX + - ", fromY=" + fromY + - ", toX=" + toX + - ", toY=" + toY + - '}'; - } - } - - public BaseItemAnimator() { - super(); - setSupportsChangeAnimations(false); - } - - public void setInterpolator(Interpolator mInterpolator) { - this.mInterpolator = mInterpolator; - } - - @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 - for (ViewHolder holder : mPendingRemovals) { - doAnimateRemove(holder); - } - mPendingRemovals.clear(); - // Next, move stuff - if (movesPending) { - final ArrayList moves = new ArrayList(); - moves.addAll(mPendingMoves); - mMovesList.add(moves); - mPendingMoves.clear(); - Runnable mover = new Runnable() { - @Override public void run() { - boolean removed = mMovesList.remove(moves); - if (!removed) { - // already canceled - return; - } - for (MoveInfo moveInfo : moves) { - animateMoveImpl(moveInfo.holder, moveInfo.fromX, moveInfo.fromY, moveInfo.toX, - moveInfo.toY); - } - moves.clear(); - } - }; - if (removalsPending) { - View view = moves.get(0).holder.itemView; - ViewCompat.postOnAnimationDelayed(view, mover, getRemoveDuration()); - } else { - mover.run(); - } - } - // Next, change stuff, to run in parallel with move animations - if (changesPending) { - final ArrayList changes = new ArrayList(); - changes.addAll(mPendingChanges); - mChangesList.add(changes); - mPendingChanges.clear(); - Runnable changer = new Runnable() { - @Override public void run() { - boolean removed = mChangesList.remove(changes); - if (!removed) { - // already canceled - return; - } - for (ChangeInfo change : changes) { - animateChangeImpl(change); - } - changes.clear(); - } - }; - if (removalsPending) { - ViewHolder holder = changes.get(0).oldHolder; - ViewCompat.postOnAnimationDelayed(holder.itemView, changer, getRemoveDuration()); - } else { - changer.run(); - } - } - // Next, add stuff - if (additionsPending) { - final ArrayList additions = new ArrayList(); - additions.addAll(mPendingAdditions); - mAdditionsList.add(additions); - mPendingAdditions.clear(); - Runnable adder = new Runnable() { - public void run() { - boolean removed = mAdditionsList.remove(additions); - if (!removed) { - // already canceled - return; - } - for (ViewHolder holder : additions) { - doAnimateAdd(holder); - } - additions.clear(); - } - }; - if (removalsPending || movesPending || changesPending) { - long removeDuration = removalsPending ? getRemoveDuration() : 0; - long moveDuration = movesPending ? getMoveDuration() : 0; - long changeDuration = changesPending ? getChangeDuration() : 0; - long totalDelay = removeDuration + Math.max(moveDuration, changeDuration); - View view = additions.get(0).itemView; - ViewCompat.postOnAnimationDelayed(view, adder, totalDelay); - } else { - adder.run(); - } - } - } - - protected void preAnimateRemoveImpl(final RecyclerView.ViewHolder holder) { - } - - protected void preAnimateAddImpl(final RecyclerView.ViewHolder holder) { - } - - protected abstract void animateRemoveImpl(final RecyclerView.ViewHolder holder); - - protected abstract void animateAddImpl(final RecyclerView.ViewHolder holder); - - private void preAnimateRemove(final RecyclerView.ViewHolder holder) { - ViewHelper.clear(holder.itemView); - - if (holder instanceof AnimateViewHolder) { - ((AnimateViewHolder) holder).preAnimateRemoveImpl(holder); - } else { - preAnimateRemoveImpl(holder); - } - } - - private void preAnimateAdd(final RecyclerView.ViewHolder holder) { - ViewHelper.clear(holder.itemView); - - if (holder instanceof AnimateViewHolder) { - ((AnimateViewHolder) holder).preAnimateAddImpl(holder); - } else { - preAnimateAddImpl(holder); - } - } - - private void doAnimateRemove(final RecyclerView.ViewHolder holder) { - if (holder instanceof AnimateViewHolder) { - ((AnimateViewHolder) holder).animateRemoveImpl(holder, new DefaultRemoveVpaListener(holder)); - } else { - animateRemoveImpl(holder); - } - - mRemoveAnimations.add(holder); - } - - private void doAnimateAdd(final RecyclerView.ViewHolder holder) { - if (holder instanceof AnimateViewHolder) { - ((AnimateViewHolder) holder).animateAddImpl(holder, new DefaultAddVpaListener(holder)); - } else { - animateAddImpl(holder); - } - - mAddAnimations.add(holder); - } - - @Override public boolean animateRemove(final ViewHolder holder) { - endAnimation(holder); - preAnimateRemove(holder); - mPendingRemovals.add(holder); - return true; - } - - protected long getRemoveDelay(final RecyclerView.ViewHolder holder) { - return Math.abs(holder.getOldPosition() * getRemoveDuration() / 4); - } - - @Override public boolean animateAdd(final ViewHolder holder) { - endAnimation(holder); - preAnimateAdd(holder); - mPendingAdditions.add(holder); - return true; - } - - protected long getAddDelay(final RecyclerView.ViewHolder holder) { - return Math.abs(holder.getAdapterPosition() * getAddDuration() / 4); - } - - @Override - public boolean animateMove(final ViewHolder holder, int fromX, int fromY, int toX, int toY) { - final View view = holder.itemView; - fromX += ViewCompat.getTranslationX(holder.itemView); - fromY += ViewCompat.getTranslationY(holder.itemView); - endAnimation(holder); - int deltaX = toX - fromX; - int deltaY = toY - fromY; - if (deltaX == 0 && deltaY == 0) { - dispatchMoveFinished(holder); - return false; - } - if (deltaX != 0) { - ViewCompat.setTranslationX(view, -deltaX); - } - if (deltaY != 0) { - ViewCompat.setTranslationY(view, -deltaY); - } - mPendingMoves.add(new MoveInfo(holder, fromX, fromY, toX, toY)); - return true; - } - - private void animateMoveImpl(final ViewHolder holder, int fromX, int fromY, int toX, int toY) { - final View view = holder.itemView; - final int deltaX = toX - fromX; - final int deltaY = toY - fromY; - if (deltaX != 0) { - ViewCompat.animate(view).translationX(0); - } - if (deltaY != 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. - mMoveAnimations.add(holder); - final ViewPropertyAnimatorCompat animation = ViewCompat.animate(view); - animation.setDuration(getMoveDuration()).setListener(new VpaListenerAdapter() { - @Override public void onAnimationStart(View view) { - dispatchMoveStarting(holder); - } - - @Override public void onAnimationCancel(View view) { - if (deltaX != 0) { - ViewCompat.setTranslationX(view, 0); - } - if (deltaY != 0) { - ViewCompat.setTranslationY(view, 0); - } - } - - @Override public void onAnimationEnd(View view) { - animation.setListener(null); - dispatchMoveFinished(holder); - mMoveAnimations.remove(holder); - dispatchFinishedWhenDone(); - } - }).start(); - } - - @Override - public boolean animateChange(ViewHolder oldHolder, ViewHolder newHolder, int fromX, int fromY, int toX, int toY) { - 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, fromX, fromY, toX, toY); - } - final float prevTranslationX = ViewCompat.getTranslationX(oldHolder.itemView); - final float prevTranslationY = ViewCompat.getTranslationY(oldHolder.itemView); - final float prevAlpha = ViewCompat.getAlpha(oldHolder.itemView); - endAnimation(oldHolder); - int deltaX = (int) (toX - fromX - prevTranslationX); - int deltaY = (int) (toY - fromY - prevTranslationY); - // recover prev translation state after ending animation - ViewCompat.setTranslationX(oldHolder.itemView, prevTranslationX); - ViewCompat.setTranslationY(oldHolder.itemView, prevTranslationY); - ViewCompat.setAlpha(oldHolder.itemView, prevAlpha); - if (newHolder != null && newHolder.itemView != null) { - // carry over translation values - endAnimation(newHolder); - ViewCompat.setTranslationX(newHolder.itemView, -deltaX); - ViewCompat.setTranslationY(newHolder.itemView, -deltaY); - ViewCompat.setAlpha(newHolder.itemView, 0); - } - mPendingChanges.add(new ChangeInfo(oldHolder, newHolder, fromX, fromY, toX, toY)); - return true; - } - - private void animateChangeImpl(final ChangeInfo changeInfo) { - final ViewHolder holder = changeInfo.oldHolder; - final View view = holder == null ? null : holder.itemView; - final ViewHolder newHolder = changeInfo.newHolder; - final View newView = newHolder != null ? newHolder.itemView : null; - if (view != null) { - mChangeAnimations.add(changeInfo.oldHolder); - final ViewPropertyAnimatorCompat oldViewAnim = - ViewCompat.animate(view).setDuration(getChangeDuration()); - oldViewAnim.translationX(changeInfo.toX - changeInfo.fromX); - oldViewAnim.translationY(changeInfo.toY - changeInfo.fromY); - oldViewAnim.alpha(0).setListener(new VpaListenerAdapter() { - @Override public void onAnimationStart(View view) { - dispatchChangeStarting(changeInfo.oldHolder, true); - } - - @Override public void onAnimationEnd(View view) { - oldViewAnim.setListener(null); - ViewCompat.setAlpha(view, 1); - ViewCompat.setTranslationX(view, 0); - ViewCompat.setTranslationY(view, 0); - dispatchChangeFinished(changeInfo.oldHolder, true); - mChangeAnimations.remove(changeInfo.oldHolder); - dispatchFinishedWhenDone(); - } - }).start(); - } - if (newView != null) { - mChangeAnimations.add(changeInfo.newHolder); - final ViewPropertyAnimatorCompat newViewAnimation = ViewCompat.animate(newView); - newViewAnimation.translationX(0).translationY(0).setDuration(getChangeDuration()). - alpha(1).setListener(new VpaListenerAdapter() { - @Override public void onAnimationStart(View view) { - dispatchChangeStarting(changeInfo.newHolder, false); - } - - @Override public void onAnimationEnd(View view) { - newViewAnimation.setListener(null); - ViewCompat.setAlpha(newView, 1); - ViewCompat.setTranslationX(newView, 0); - ViewCompat.setTranslationY(newView, 0); - dispatchChangeFinished(changeInfo.newHolder, false); - mChangeAnimations.remove(changeInfo.newHolder); - dispatchFinishedWhenDone(); - } - }).start(); - } - } - - private void endChangeAnimation(List infoList, 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); - } - } - } - } - - private void endChangeAnimationIfNecessary(ChangeInfo changeInfo) { - if (changeInfo.oldHolder != null) { - endChangeAnimationIfNecessary(changeInfo, changeInfo.oldHolder); - } - if (changeInfo.newHolder != null) { - endChangeAnimationIfNecessary(changeInfo, changeInfo.newHolder); - } - } - - private boolean endChangeAnimationIfNecessary(ChangeInfo changeInfo, 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; - } - ViewCompat.setAlpha(item.itemView, 1); - ViewCompat.setTranslationX(item.itemView, 0); - ViewCompat.setTranslationY(item.itemView, 0); - dispatchChangeFinished(item, oldItem); - return true; - } - - @Override public void endAnimation(ViewHolder item) { - final View view = item.itemView; - // this will trigger end callback which should set properties to their target values. - ViewCompat.animate(view).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) { - ViewCompat.setTranslationY(view, 0); - ViewCompat.setTranslationX(view, 0); - dispatchMoveFinished(item); - mPendingMoves.remove(i); - } - } - endChangeAnimation(mPendingChanges, item); - if (mPendingRemovals.remove(item)) { - ViewHelper.clear(item.itemView); - dispatchRemoveFinished(item); - } - if (mPendingAdditions.remove(item)) { - ViewHelper.clear(item.itemView); - dispatchAddFinished(item); - } - - for (int i = mChangesList.size() - 1; i >= 0; i--) { - ArrayList changes = mChangesList.get(i); - endChangeAnimation(changes, item); - if (changes.isEmpty()) { - mChangesList.remove(i); - } - } - for (int i = mMovesList.size() - 1; i >= 0; i--) { - ArrayList moves = mMovesList.get(i); - for (int j = moves.size() - 1; j >= 0; j--) { - MoveInfo moveInfo = moves.get(j); - if (moveInfo.holder == item) { - ViewCompat.setTranslationY(view, 0); - ViewCompat.setTranslationX(view, 0); - dispatchMoveFinished(item); - moves.remove(j); - if (moves.isEmpty()) { - mMovesList.remove(i); - } - break; - } - } - } - for (int i = mAdditionsList.size() - 1; i >= 0; i--) { - ArrayList additions = mAdditionsList.get(i); - if (additions.remove(item)) { - ViewHelper.clear(item.itemView); - dispatchAddFinished(item); - if (additions.isEmpty()) { - mAdditionsList.remove(i); - } - } - } - - // animations should be ended by the cancel above. - if (mRemoveAnimations.remove(item) && DEBUG) { - throw new IllegalStateException( - "after animation is cancelled, item should not be in " + "mRemoveAnimations list"); - } - - if (mAddAnimations.remove(item) && DEBUG) { - throw new IllegalStateException( - "after animation is cancelled, item should not be in " + "mAddAnimations list"); - } - - if (mChangeAnimations.remove(item) && DEBUG) { - throw new IllegalStateException( - "after animation is cancelled, item should not be in " + "mChangeAnimations list"); - } - - if (mMoveAnimations.remove(item) && DEBUG) { - throw new IllegalStateException( - "after animation is cancelled, item should not be in " + "mMoveAnimations list"); - } - dispatchFinishedWhenDone(); - } - - @Override public boolean isRunning() { - 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 #dispatchAnimationsFinished() to notify any - * listeners. - */ - private void dispatchFinishedWhenDone() { - if (!isRunning()) { - dispatchAnimationsFinished(); - } - } - - @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; - ViewCompat.setTranslationY(view, 0); - ViewCompat.setTranslationX(view, 0); - dispatchMoveFinished(item.holder); - mPendingMoves.remove(i); - } - count = mPendingRemovals.size(); - for (int i = count - 1; i >= 0; i--) { - ViewHolder item = mPendingRemovals.get(i); - dispatchRemoveFinished(item); - mPendingRemovals.remove(i); - } - count = mPendingAdditions.size(); - for (int i = count - 1; i >= 0; i--) { - ViewHolder item = mPendingAdditions.get(i); - ViewHelper.clear(item.itemView); - 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 moves = mMovesList.get(i); - count = moves.size(); - for (int j = count - 1; j >= 0; j--) { - MoveInfo moveInfo = moves.get(j); - ViewHolder item = moveInfo.holder; - View view = item.itemView; - ViewCompat.setTranslationY(view, 0); - ViewCompat.setTranslationX(view, 0); - dispatchMoveFinished(moveInfo.holder); - moves.remove(j); - if (moves.isEmpty()) { - mMovesList.remove(moves); - } - } - } - listCount = mAdditionsList.size(); - for (int i = listCount - 1; i >= 0; i--) { - ArrayList additions = mAdditionsList.get(i); - count = additions.size(); - for (int j = count - 1; j >= 0; j--) { - ViewHolder item = additions.get(j); - View view = item.itemView; - ViewCompat.setAlpha(view, 1); - dispatchAddFinished(item); - //this check prevent exception when removal already happened during finishing animation - if (j < additions.size()) { - additions.remove(j); - } - if (additions.isEmpty()) { - mAdditionsList.remove(additions); - } - } - } - listCount = mChangesList.size(); - for (int i = listCount - 1; i >= 0; i--) { - ArrayList 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(); - } - - void cancelAll(List 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) { - } - } - - protected class DefaultAddVpaListener extends VpaListenerAdapter { - - RecyclerView.ViewHolder mViewHolder; - - public DefaultAddVpaListener(final RecyclerView.ViewHolder holder) { - mViewHolder = holder; - } - - @Override public void onAnimationStart(View view) { - dispatchAddStarting(mViewHolder); - } - - @Override public void onAnimationCancel(View view) { - ViewHelper.clear(view); - } - - @Override public void onAnimationEnd(View view) { - ViewHelper.clear(view); - dispatchAddFinished(mViewHolder); - mAddAnimations.remove(mViewHolder); - dispatchFinishedWhenDone(); - } - } - - protected class DefaultRemoveVpaListener extends VpaListenerAdapter { - - RecyclerView.ViewHolder mViewHolder; - - public DefaultRemoveVpaListener(final RecyclerView.ViewHolder holder) { - mViewHolder = holder; - } - - @Override public void onAnimationStart(View view) { - dispatchRemoveStarting(mViewHolder); - } - - @Override public void onAnimationCancel(View view) { - ViewHelper.clear(view); - } - - @Override public void onAnimationEnd(View view) { - ViewHelper.clear(view); - dispatchRemoveFinished(mViewHolder); - mRemoveAnimations.remove(mViewHolder); - dispatchFinishedWhenDone(); - } - } -} diff --git a/animators/src/main/java/jp/wasabeef/recyclerview/animators/BaseItemAnimator.kt b/animators/src/main/java/jp/wasabeef/recyclerview/animators/BaseItemAnimator.kt new file mode 100644 index 0000000..afbbbf1 --- /dev/null +++ b/animators/src/main/java/jp/wasabeef/recyclerview/animators/BaseItemAnimator.kt @@ -0,0 +1,653 @@ +package jp.wasabeef.recyclerview.animators + +import android.view.View +import android.view.animation.DecelerateInterpolator +import android.view.animation.Interpolator +import androidx.core.view.ViewCompat +import androidx.core.view.ViewPropertyAnimatorListener +import androidx.recyclerview.widget.RecyclerView +import androidx.recyclerview.widget.SimpleItemAnimator +import jp.wasabeef.recyclerview.animators.holder.AnimateViewHolder +import jp.wasabeef.recyclerview.internal.ViewHelper +import java.util.* +import kotlin.math.abs + +/* + * Copyright (C) 2018 Wasabeef + * Copyright (C) 2014 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. + * + */ +abstract class BaseItemAnimator : SimpleItemAnimator() { + private val mPendingRemovals = ArrayList() + private val mPendingAdditions = ArrayList() + private val mPendingMoves = ArrayList() + private val mPendingChanges = ArrayList() + private val mAdditionsList = ArrayList>() + private val mMovesList = ArrayList>() + private val mChangesList = ArrayList>() + protected var mAddAnimations = ArrayList() + private val mMoveAnimations = ArrayList() + protected var mRemoveAnimations = ArrayList() + private val mChangeAnimations = ArrayList() + private var mAddDelay: ((holder: RecyclerView.ViewHolder) -> Long)? = null + private var mRemoveDelay: ((holder: RecyclerView.ViewHolder) -> Long)? = null + + @JvmField + protected var mInterpolator: Interpolator = DecelerateInterpolator() + + private class MoveInfo(var holder: RecyclerView.ViewHolder, var fromX: Int, var fromY: Int, var toX: Int, var toY: Int) + + private class ChangeInfo private constructor(oldHolder: RecyclerView.ViewHolder, newHolder: RecyclerView.ViewHolder) { + var oldHolder: RecyclerView.ViewHolder? = oldHolder + var newHolder: RecyclerView.ViewHolder? = newHolder + var fromX = 0 + var fromY = 0 + var toX = 0 + var toY = 0 + + constructor(oldHolder: RecyclerView.ViewHolder, newHolder: RecyclerView.ViewHolder, fromX: Int, fromY: Int, toX: Int, + toY: Int) : this(oldHolder, newHolder) { + this.fromX = fromX + this.fromY = fromY + this.toX = toX + this.toY = toY + } + + override fun toString(): String { + return "ChangeInfo{" + + "oldHolder=" + oldHolder + + ", newHolder=" + newHolder + + ", fromX=" + fromX + + ", fromY=" + fromY + + ", toX=" + toX + + ", toY=" + toY + + '}' + } + + } + + fun setInterpolator(mInterpolator: Interpolator) { + this.mInterpolator = mInterpolator + } + + fun setAddDelay(customFunction: ((holder: RecyclerView.ViewHolder) -> Long)) { + mAddDelay = customFunction + } + + fun setRemoveDelay(customFunction: ((holder: RecyclerView.ViewHolder) -> Long)) { + mRemoveDelay = customFunction + } + + override fun runPendingAnimations() { + val removalsPending = mPendingRemovals.isNotEmpty() + val movesPending = mPendingMoves.isNotEmpty() + val changesPending = mPendingChanges.isNotEmpty() + val additionsPending = mPendingAdditions.isNotEmpty() + if (!removalsPending && !movesPending && !additionsPending && !changesPending) { + // nothing to animate + return + } + // First, remove stuff + for (holder in mPendingRemovals) { + doAnimateRemove(holder) + } + mPendingRemovals.clear() + // Next, move stuff + if (movesPending) { + val moves = ArrayList() + moves.addAll(mPendingMoves) + mMovesList.add(moves) + mPendingMoves.clear() + val mover = Runnable { + val removed = mMovesList.remove(moves) + if (!removed) { + // already canceled + return@Runnable + } + for (moveInfo in moves) { + animateMoveImpl(moveInfo.holder, moveInfo.fromX, moveInfo.fromY, moveInfo.toX, + moveInfo.toY) + } + moves.clear() + } + if (removalsPending) { + val view = moves[0].holder.itemView + ViewCompat.postOnAnimationDelayed(view, mover, removeDuration) + } else { + mover.run() + } + } + // Next, change stuff, to run in parallel with move animations + if (changesPending) { + val changes = ArrayList() + changes.addAll(mPendingChanges) + mChangesList.add(changes) + mPendingChanges.clear() + val changer = Runnable { + val removed = mChangesList.remove(changes) + if (!removed) { + // already canceled + return@Runnable + } + for (change in changes) { + animateChangeImpl(change) + } + changes.clear() + } + if (removalsPending) { + val holder = changes[0].oldHolder + ViewCompat.postOnAnimationDelayed(holder!!.itemView, changer, removeDuration) + } else { + changer.run() + } + } + // Next, add stuff + if (additionsPending) { + val additions = ArrayList() + additions.addAll(mPendingAdditions) + mAdditionsList.add(additions) + mPendingAdditions.clear() + val adder = Runnable { + val removed = mAdditionsList.remove(additions) + if (!removed) { + // already canceled + return@Runnable + } + for (holder in additions) { + doAnimateAdd(holder) + } + additions.clear() + } + if (removalsPending || movesPending || changesPending) { + val removeDuration = if (removalsPending) removeDuration else 0 + val moveDuration = if (movesPending) moveDuration else 0 + val changeDuration = if (changesPending) changeDuration else 0 + val totalDelay = removeDuration + moveDuration.coerceAtLeast(changeDuration) + val view = additions[0].itemView + ViewCompat.postOnAnimationDelayed(view, adder, totalDelay) + } else { + adder.run() + } + } + } + + protected open fun preAnimateRemoveImpl(holder: RecyclerView.ViewHolder?) {} + protected open fun preAnimateAddImpl(holder: RecyclerView.ViewHolder?) {} + protected abstract fun animateRemoveImpl(holder: RecyclerView.ViewHolder?) + protected abstract fun animateAddImpl(holder: RecyclerView.ViewHolder?) + private fun preAnimateRemove(holder: RecyclerView.ViewHolder) { + ViewHelper.clear(holder.itemView) + if (holder is AnimateViewHolder) { + (holder as AnimateViewHolder).preAnimateRemoveImpl(holder) + } else { + preAnimateRemoveImpl(holder) + } + } + + private fun preAnimateAdd(holder: RecyclerView.ViewHolder) { + ViewHelper.clear(holder.itemView) + if (holder is AnimateViewHolder) { + (holder as AnimateViewHolder).preAnimateAddImpl(holder) + } else { + preAnimateAddImpl(holder) + } + } + + private fun doAnimateRemove(holder: RecyclerView.ViewHolder) { + if (holder is AnimateViewHolder) { + (holder as AnimateViewHolder).animateRemoveImpl(holder, DefaultRemoveVpaListener(holder)) + } else { + animateRemoveImpl(holder) + } + mRemoveAnimations.add(holder) + } + + private fun doAnimateAdd(holder: RecyclerView.ViewHolder) { + if (holder is AnimateViewHolder) { + (holder as AnimateViewHolder).animateAddImpl(holder, DefaultAddVpaListener(holder)) + } else { + animateAddImpl(holder) + } + mAddAnimations.add(holder) + } + + override fun animateRemove(holder: RecyclerView.ViewHolder): Boolean { + endAnimation(holder) + preAnimateRemove(holder) + mPendingRemovals.add(holder) + return true + } + + protected fun getRemoveDelay(holder: RecyclerView.ViewHolder): Long { + mRemoveDelay?.let { return it(holder) } + ?: return abs(holder.oldPosition * removeDuration / 4) + } + + override fun animateAdd(holder: RecyclerView.ViewHolder): Boolean { + endAnimation(holder) + preAnimateAdd(holder) + mPendingAdditions.add(holder) + return true + } + + protected fun getAddDelay(holder: RecyclerView.ViewHolder): Long { + mAddDelay?.let { return it(holder) } + ?: return abs(holder.adapterPosition * addDuration / 4) + } + + override fun animateMove(holder: RecyclerView.ViewHolder, fromX: Int, fromY: Int, toX: Int, toY: Int): Boolean { + var fX = fromX + var fY = fromY + val view = holder.itemView + fX += view.translationX.toInt() + fY += view.translationY.toInt() + endAnimation(holder) + val deltaX = toX - fX + val deltaY = toY - fY + if (deltaX == 0 && deltaY == 0) { + dispatchMoveFinished(holder) + return false + } + if (deltaX != 0) { + view.translationX = -deltaX.toFloat() + } + if (deltaY != 0) { + view.translationY = -deltaY.toFloat() + } + mPendingMoves.add(MoveInfo(holder, fX, fY, toX, toY)) + return true + } + + private fun animateMoveImpl(holder: RecyclerView.ViewHolder, fromX: Int, fromY: Int, toX: Int, toY: Int) { + val view = holder.itemView + val deltaX = toX - fromX + val deltaY = toY - fromY + if (deltaX != 0) { + ViewCompat.animate(view).translationX(0f) + } + if (deltaY != 0) { + ViewCompat.animate(view).translationY(0f) + } + // 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. + mMoveAnimations.add(holder) + val animation = ViewCompat.animate(view) + animation.setDuration(moveDuration).setListener(object : VpaListenerAdapter() { + override fun onAnimationStart(view: View) { + dispatchMoveStarting(holder) + } + + override fun onAnimationCancel(view: View) { + if (deltaX != 0) { + view.translationX = 0f + } + if (deltaY != 0) { + view.translationY = 0f + } + } + + override fun onAnimationEnd(view: View) { + animation.setListener(null) + dispatchMoveFinished(holder) + mMoveAnimations.remove(holder) + dispatchFinishedWhenDone() + } + }).start() + } + + override fun animateChange(oldHolder: RecyclerView.ViewHolder, newHolder: RecyclerView.ViewHolder, fromX: Int, fromY: Int, toX: Int, toY: Int): Boolean { + 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, fromX, fromY, toX, toY) + } + val prevTranslationX = oldHolder.itemView.translationX + val prevTranslationY = oldHolder.itemView.translationY + val prevAlpha = oldHolder.itemView.alpha + endAnimation(oldHolder) + val deltaX = (toX - fromX - prevTranslationX).toInt() + val deltaY = (toY - fromY - prevTranslationY).toInt() + // recover prev translation state after ending animation + oldHolder.itemView.translationX = prevTranslationX + oldHolder.itemView.translationY = prevTranslationY + oldHolder.itemView.alpha = prevAlpha + // carry over translation values + endAnimation(newHolder) + newHolder.itemView.translationX = -deltaX.toFloat() + newHolder.itemView.translationY = -deltaY.toFloat() + newHolder.itemView.alpha = 0f + mPendingChanges.add(ChangeInfo(oldHolder, newHolder, fromX, fromY, toX, toY)) + return true + } + + private fun animateChangeImpl(changeInfo: ChangeInfo) { + val holder = changeInfo.oldHolder + val view = holder?.itemView + val newHolder = changeInfo.newHolder + val newView = newHolder?.itemView + if (view != null) { + mChangeAnimations.add(changeInfo.oldHolder) + val oldViewAnim = ViewCompat.animate(view).setDuration(changeDuration) + oldViewAnim.translationX(changeInfo.toX - changeInfo.fromX.toFloat()) + oldViewAnim.translationY(changeInfo.toY - changeInfo.fromY.toFloat()) + oldViewAnim.alpha(0f).setListener(object : VpaListenerAdapter() { + override fun onAnimationStart(view: View) { + dispatchChangeStarting(changeInfo.oldHolder, true) + } + + override fun onAnimationEnd(view: View) { + oldViewAnim.setListener(null) + view.alpha = 1f + view.translationX = 0f + view.translationY = 0f + dispatchChangeFinished(changeInfo.oldHolder, true) + mChangeAnimations.remove(changeInfo.oldHolder) + dispatchFinishedWhenDone() + } + }).start() + } + if (newView != null) { + mChangeAnimations.add(changeInfo.newHolder) + val newViewAnimation = ViewCompat.animate(newView) + newViewAnimation.translationX(0f).translationY(0f).setDuration(changeDuration).alpha(1f).setListener(object : VpaListenerAdapter() { + override fun onAnimationStart(view: View) { + dispatchChangeStarting(changeInfo.newHolder, false) + } + + override fun onAnimationEnd(view: View) { + newViewAnimation.setListener(null) + newView.alpha = 1f + newView.translationX = 0f + newView.translationY = 0f + dispatchChangeFinished(changeInfo.newHolder, false) + mChangeAnimations.remove(changeInfo.newHolder) + dispatchFinishedWhenDone() + } + }).start() + } + } + + private fun endChangeAnimation(infoList: MutableList, item: RecyclerView.ViewHolder) { + for (i in infoList.indices.reversed()) { + val changeInfo = infoList[i] + if (endChangeAnimationIfNecessary(changeInfo, item)) { + if (changeInfo.oldHolder == null && changeInfo.newHolder == null) { + infoList.remove(changeInfo) + } + } + } + } + + private fun endChangeAnimationIfNecessary(changeInfo: ChangeInfo) { + if (changeInfo.oldHolder != null) { + endChangeAnimationIfNecessary(changeInfo, changeInfo.oldHolder) + } + if (changeInfo.newHolder != null) { + endChangeAnimationIfNecessary(changeInfo, changeInfo.newHolder) + } + } + + private fun endChangeAnimationIfNecessary(changeInfo: ChangeInfo, item: RecyclerView.ViewHolder?): Boolean { + var oldItem = false + when { + changeInfo.newHolder === item -> { + changeInfo.newHolder = null + } + changeInfo.oldHolder === item -> { + changeInfo.oldHolder = null + oldItem = true + } + else -> { + return false + } + } + item!!.itemView.alpha = 1f + item.itemView.translationX = 0f + item.itemView.translationY = 0f + dispatchChangeFinished(item, oldItem) + return true + } + + override fun endAnimation(item: RecyclerView.ViewHolder) { + val view = item.itemView + // this will trigger end callback which should set properties to their target values. + ViewCompat.animate(view).cancel() + // TODO if some other animations are chained to end, how do we cancel them as well? + for (i in mPendingMoves.indices.reversed()) { + val moveInfo = mPendingMoves[i] + if (moveInfo.holder === item) { + view.translationY = 0f + view.translationX = 0f + dispatchMoveFinished(item) + mPendingMoves.removeAt(i) + } + } + endChangeAnimation(mPendingChanges, item) + if (mPendingRemovals.remove(item)) { + ViewHelper.clear(item.itemView) + dispatchRemoveFinished(item) + } + if (mPendingAdditions.remove(item)) { + ViewHelper.clear(item.itemView) + dispatchAddFinished(item) + } + for (i in mChangesList.indices.reversed()) { + val changes = mChangesList[i] + endChangeAnimation(changes, item) + if (changes.isEmpty()) { + mChangesList.removeAt(i) + } + } + for (i in mMovesList.indices.reversed()) { + val moves = mMovesList[i] + for (j in moves.indices.reversed()) { + val moveInfo = moves[j] + if (moveInfo.holder === item) { + view.translationY = 0f + view.translationX = 0f + dispatchMoveFinished(item) + moves.removeAt(j) + if (moves.isEmpty()) { + mMovesList.removeAt(i) + } + break + } + } + } + for (i in mAdditionsList.indices.reversed()) { + val additions = mAdditionsList[i] + if (additions.remove(item)) { + ViewHelper.clear(item.itemView) + dispatchAddFinished(item) + if (additions.isEmpty()) { + mAdditionsList.removeAt(i) + } + } + } + + // animations should be ended by the cancel above. + check(!(mRemoveAnimations.remove(item) && DEBUG)) { "after animation is cancelled, item should not be in " + "mRemoveAnimations list" } + check(!(mAddAnimations.remove(item) && DEBUG)) { "after animation is cancelled, item should not be in " + "mAddAnimations list" } + check(!(mChangeAnimations.remove(item) && DEBUG)) { "after animation is cancelled, item should not be in " + "mChangeAnimations list" } + check(!(mMoveAnimations.remove(item) && DEBUG)) { "after animation is cancelled, item should not be in " + "mMoveAnimations list" } + dispatchFinishedWhenDone() + } + + override fun isRunning(): Boolean { + return mPendingAdditions.isNotEmpty() || + mPendingChanges.isNotEmpty() || + mPendingMoves.isNotEmpty() || + mPendingRemovals.isNotEmpty() || + mMoveAnimations.isNotEmpty() || + mRemoveAnimations.isNotEmpty() || + mAddAnimations.isNotEmpty() || + mChangeAnimations.isNotEmpty() || + mMovesList.isNotEmpty() || + mAdditionsList.isNotEmpty() || + mChangesList.isNotEmpty() + } + + /** + * Check the state of currently pending and running animations. If there are none + * pending/running, call #dispatchAnimationsFinished() to notify any + * listeners. + */ + private fun dispatchFinishedWhenDone() { + if (!isRunning) { + dispatchAnimationsFinished() + } + } + + override fun endAnimations() { + var count = mPendingMoves.size + for (i in count - 1 downTo 0) { + val item = mPendingMoves[i] + val view = item.holder.itemView + view.translationY = 0f + view.translationX = 0f + dispatchMoveFinished(item.holder) + mPendingMoves.removeAt(i) + } + count = mPendingRemovals.size + for (i in count - 1 downTo 0) { + val item = mPendingRemovals[i] + dispatchRemoveFinished(item) + mPendingRemovals.removeAt(i) + } + count = mPendingAdditions.size + for (i in count - 1 downTo 0) { + val item = mPendingAdditions[i] + ViewHelper.clear(item.itemView) + dispatchAddFinished(item) + mPendingAdditions.removeAt(i) + } + count = mPendingChanges.size + for (i in count - 1 downTo 0) { + endChangeAnimationIfNecessary(mPendingChanges[i]) + } + mPendingChanges.clear() + if (!isRunning) { + return + } + var listCount = mMovesList.size + for (i in listCount - 1 downTo 0) { + val moves = mMovesList[i] + count = moves.size + for (j in count - 1 downTo 0) { + val moveInfo = moves[j] + val item = moveInfo.holder + val view = item.itemView + view.translationY = 0f + view.translationX = 0f + dispatchMoveFinished(moveInfo.holder) + moves.removeAt(j) + if (moves.isEmpty()) { + mMovesList.remove(moves) + } + } + } + listCount = mAdditionsList.size + for (i in listCount - 1 downTo 0) { + val additions = mAdditionsList[i] + count = additions.size + for (j in count - 1 downTo 0) { + val item = additions[j] + val view = item.itemView + view.alpha = 1f + dispatchAddFinished(item) + //this check prevent exception when removal already happened during finishing animation + if (j < additions.size) { + additions.removeAt(j) + } + if (additions.isEmpty()) { + mAdditionsList.remove(additions) + } + } + } + listCount = mChangesList.size + for (i in listCount - 1 downTo 0) { + val changes = mChangesList[i] + count = changes.size + for (j in count - 1 downTo 0) { + endChangeAnimationIfNecessary(changes[j]) + if (changes.isEmpty()) { + mChangesList.remove(changes) + } + } + } + cancelAll(mRemoveAnimations) + cancelAll(mMoveAnimations) + cancelAll(mAddAnimations) + cancelAll(mChangeAnimations) + dispatchAnimationsFinished() + } + + private fun cancelAll(viewHolders: List) { + for (i in viewHolders.indices.reversed()) { + ViewCompat.animate(viewHolders[i]!!.itemView).cancel() + } + } + + open class VpaListenerAdapter : ViewPropertyAnimatorListener { + override fun onAnimationStart(view: View) {} + override fun onAnimationEnd(view: View) {} + override fun onAnimationCancel(view: View) {} + } + + inner class DefaultAddVpaListener(var mViewHolder: RecyclerView.ViewHolder) : VpaListenerAdapter() { + override fun onAnimationStart(view: View) { + dispatchAddStarting(mViewHolder) + } + + override fun onAnimationCancel(view: View) { + ViewHelper.clear(view) + } + + override fun onAnimationEnd(view: View) { + ViewHelper.clear(view) + dispatchAddFinished(mViewHolder) + mAddAnimations.remove(mViewHolder) + dispatchFinishedWhenDone() + } + + } + + inner class DefaultRemoveVpaListener(var mViewHolder: RecyclerView.ViewHolder) : VpaListenerAdapter() { + override fun onAnimationStart(view: View) { + dispatchRemoveStarting(mViewHolder) + } + + override fun onAnimationCancel(view: View) { + ViewHelper.clear(view) + } + + override fun onAnimationEnd(view: View) { + ViewHelper.clear(view) + dispatchRemoveFinished(mViewHolder) + mRemoveAnimations.remove(mViewHolder) + dispatchFinishedWhenDone() + } + + } + + companion object { + private const val DEBUG = false + } + + init { + supportsChangeAnimations = false + } +} \ No newline at end of file diff --git a/build.gradle b/build.gradle index e709560..569a226 100644 --- a/build.gradle +++ b/build.gradle @@ -1,13 +1,13 @@ // Top-level build file where you can add configuration options common to all sub-projects/modules. buildscript { - ext.kotlin_version = '1.3.31' + ext.kotlin_version = '1.3.72' repositories { google() jcenter() } dependencies { - classpath 'com.android.tools.build:gradle:3.6.0-alpha03' + classpath 'com.android.tools.build:gradle:4.0.0' classpath 'com.jfrog.bintray.gradle:gradle-bintray-plugin:1.8.4' classpath 'com.github.dcendents:android-maven-gradle-plugin:2.1' classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" diff --git a/example/src/main/java/jp/wasabeef/example/recyclerview/AdapterSampleActivity.kt b/example/src/main/java/jp/wasabeef/example/recyclerview/AdapterSampleActivity.kt index 1eb4488..409f6e1 100644 --- a/example/src/main/java/jp/wasabeef/example/recyclerview/AdapterSampleActivity.kt +++ b/example/src/main/java/jp/wasabeef/example/recyclerview/AdapterSampleActivity.kt @@ -87,6 +87,7 @@ class AdapterSampleActivity : AppCompatActivity() { } recyclerView.itemAnimator = FadeInAnimator() + (recyclerView.itemAnimator as FadeInAnimator).addDuration = 1000 val adapter = MainAdapter(this, SampleData.LIST.toMutableList()) recyclerView.adapter = AlphaInAnimationAdapter(adapter).apply { setFirstOnly(true) diff --git a/example/src/main/java/jp/wasabeef/example/recyclerview/AnimatorSampleActivity.kt b/example/src/main/java/jp/wasabeef/example/recyclerview/AnimatorSampleActivity.kt index c6f1409..d9ccb7b 100644 --- a/example/src/main/java/jp/wasabeef/example/recyclerview/AnimatorSampleActivity.kt +++ b/example/src/main/java/jp/wasabeef/example/recyclerview/AnimatorSampleActivity.kt @@ -37,73 +37,82 @@ import jp.wasabeef.recyclerview.animators.SlideInUpAnimator */ class AnimatorSampleActivity : AppCompatActivity() { - internal enum class Type(val animator: BaseItemAnimator) { - FadeIn(FadeInAnimator()), - FadeInDown(FadeInDownAnimator()), - FadeInUp(FadeInUpAnimator()), - FadeInLeft(FadeInLeftAnimator()), - FadeInRight(FadeInRightAnimator()), - Landing(LandingAnimator()), - ScaleIn(ScaleInAnimator()), - ScaleInTop(ScaleInTopAnimator()), - ScaleInBottom(ScaleInBottomAnimator()), - ScaleInLeft(ScaleInLeftAnimator()), - ScaleInRight(ScaleInRightAnimator()), - FlipInTopX(FlipInTopXAnimator()), - FlipInBottomX(FlipInBottomXAnimator()), - FlipInLeftY(FlipInLeftYAnimator()), - FlipInRightY(FlipInRightYAnimator()), - SlideInLeft(SlideInLeftAnimator()), - SlideInRight(SlideInRightAnimator()), - SlideInDown(SlideInDownAnimator()), - SlideInUp(SlideInUpAnimator()), - OvershootInRight(OvershootInRightAnimator(1.0f)), - OvershootInLeft(OvershootInLeftAnimator(1.0f)) - } + internal enum class Type(val animator: BaseItemAnimator) { + FadeIn(FadeInAnimator()), + FadeInDown(FadeInDownAnimator()), + FadeInUp(FadeInUpAnimator()), + FadeInLeft(FadeInLeftAnimator()), + FadeInRight(FadeInRightAnimator()), + Landing(LandingAnimator()), + ScaleIn(ScaleInAnimator()), + ScaleInTop(ScaleInTopAnimator()), + ScaleInBottom(ScaleInBottomAnimator()), + ScaleInLeft(ScaleInLeftAnimator()), + ScaleInRight(ScaleInRightAnimator()), + FlipInTopX(FlipInTopXAnimator()), + FlipInBottomX(FlipInBottomXAnimator()), + FlipInLeftY(FlipInLeftYAnimator()), + FlipInRightY(FlipInRightYAnimator()), + SlideInLeft(SlideInLeftAnimator()), + SlideInRight(SlideInRightAnimator()), + SlideInDown(SlideInDownAnimator()), + SlideInUp(SlideInUpAnimator()), + OvershootInRight(OvershootInRightAnimator(1.0f)), + OvershootInLeft(OvershootInLeftAnimator(1.0f)) + } - private val adapter = MainAdapter(this, SampleData.LIST.toMutableList()) + private val adapter = MainAdapter(this, SampleData.LIST.toMutableList()) - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - setContentView(R.layout.activity_animator_sample) + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContentView(R.layout.activity_animator_sample) + setContentView(R.layout.activity_animator_sample) - setSupportActionBar(findViewById(R.id.tool_bar)) - supportActionBar!!.setDisplayShowTitleEnabled(false) + setSupportActionBar(findViewById(R.id.tool_bar)) + supportActionBar!!.setDisplayShowTitleEnabled(false) - val recyclerView = findViewById(R.id.list) - recyclerView.apply { - itemAnimator = SlideInLeftAnimator() - adapter = this@AnimatorSampleActivity.adapter + val recyclerView = findViewById(R.id.list) + recyclerView.apply { + itemAnimator = SlideInLeftAnimator() + adapter = this@AnimatorSampleActivity.adapter - layoutManager = if (intent.getBooleanExtra(MainActivity.KEY_GRID, true)) { - GridLayoutManager(context, 2) - } else { - LinearLayoutManager(context) - } - } + layoutManager = if (intent.getBooleanExtra(MainActivity.KEY_GRID, true)) { + GridLayoutManager(context, 2) + } else { + LinearLayoutManager(context) + } + } - val spinner = findViewById(R.id.spinner) - val spinnerAdapter = ArrayAdapter(this, android.R.layout.simple_list_item_1) - for (type in Type.values()) { - spinnerAdapter.add(type.name) - } - spinner.adapter = spinnerAdapter - spinner.onItemSelectedListener = object : AdapterView.OnItemSelectedListener { - override fun onItemSelected(parent: AdapterView<*>, view: View, position: Int, id: Long) { - recyclerView.itemAnimator = Type.values()[position].animator - recyclerView.itemAnimator!!.addDuration = 500 - recyclerView.itemAnimator!!.removeDuration = 500 - } + val spinner = findViewById(R.id.spinner) + val spinnerAdapter = ArrayAdapter(this, android.R.layout.simple_list_item_1) + for (type in Type.values()) { + spinnerAdapter.add(type.name) + } + spinner.adapter = spinnerAdapter + spinner.onItemSelectedListener = object : AdapterView.OnItemSelectedListener { + override fun onItemSelected(parent: AdapterView<*>, view: View, position: Int, id: Long) { + recyclerView.itemAnimator = Type.values()[position].animator + recyclerView.itemAnimator!!.addDuration = 500 + recyclerView.itemAnimator!!.removeDuration = 500 + fun tmpAddDelay(holder: RecyclerView.ViewHolder) :Long { + return 600 + } + fun tmpRemoveDelay(holder: RecyclerView.ViewHolder) :Long { + return 0 + } + (recyclerView.itemAnimator!! as BaseItemAnimator).setAddDelay(::tmpAddDelay) + (recyclerView.itemAnimator!! as BaseItemAnimator).setRemoveDelay(::tmpRemoveDelay) + } - override fun onNothingSelected(parent: AdapterView<*>) { - // no-op - } - } + override fun onNothingSelected(parent: AdapterView<*>) { + // no-op + } + } - findViewById(R.id.add).setOnClickListener { adapter.add("newly added item", 1) } + findViewById(R.id.add).setOnClickListener { adapter.add("newly added item", 1) } - findViewById(R.id.del).setOnClickListener { adapter.remove(1) } - } + findViewById(R.id.del).setOnClickListener { adapter.remove(1) } + } } diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index f4d7b2b..d60664c 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,6 @@ +#Thu Jul 09 13:09:53 IRDT 2020 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-5.4.1-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-6.1.1-all.zip