From 32e2dd600be20cb059831b650235ebbacf0d85da Mon Sep 17 00:00:00 2001 From: Mike Penz Date: Sat, 9 Jan 2016 18:56:06 +0100 Subject: [PATCH 1/3] * initial commit --- .gitignore | 4 + .../res/drawable-hdpi/ic_launcher.png | Bin 0 -> 1737 bytes .../res/drawable-mdpi/ic_launcher.png | Bin 0 -> 1277 bytes .../res/drawable-xhdpi/ic_launcher.png | Bin 0 -> 2309 bytes .../res/drawable-xxhdpi/ic_launcher.png | Bin 0 -> 3575 bytes .../res/drawable-xxxhdpi/ic_launcher.png | Bin 0 -> 5174 bytes DEV/ic_launcher/web_hi_res_512.png | Bin 0 -> 18882 bytes DEV/original/DefaultItemAnimator.java | 645 +++++++++++++++ LICENSE | 1 + README.md | 58 +- app/.gitignore | 1 + app/build.gradle | 74 ++ app/proguard-rules.pro | 17 + app/src/main/AndroidManifest.xml | 21 + .../itemanimators/app/SampleActivity.java | 242 ++++++ .../app/dummy/ImageDummyData.java | 66 ++ .../itemanimators/app/items/ImageItem.java | 132 +++ .../itemanimators/app/items/SampleItem.java | 134 +++ app/src/main/res/anim/alpha_on.xml | 6 + .../main/res/drawable-hdpi/ic_launcher.png | Bin 0 -> 1737 bytes .../main/res/drawable-mdpi/ic_launcher.png | Bin 0 -> 1277 bytes .../main/res/drawable-xhdpi/ic_launcher.png | Bin 0 -> 2309 bytes .../main/res/drawable-xxhdpi/ic_launcher.png | Bin 0 -> 3575 bytes .../main/res/drawable-xxxhdpi/ic_launcher.png | Bin 0 -> 5174 bytes app/src/main/res/drawable/gradient.xml | 10 + app/src/main/res/layout/activity_sample.xml | 35 + app/src/main/res/layout/image_item.xml | 65 ++ app/src/main/res/layout/sample_item.xml | 36 + app/src/main/res/menu/menu.xml | 26 + app/src/main/res/values/colors.xml | 7 + app/src/main/res/values/ids.xml | 6 + app/src/main/res/values/integers.xml | 4 + app/src/main/res/values/strings.xml | 5 + build.gradle | 30 + gradle.properties | 35 + gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 53637 bytes gradle/wrapper/gradle-wrapper.properties | 6 + gradlew | 160 ++++ gradlew.bat | 90 +++ library/.gitignore | 1 + library/build.gradle | 32 + library/gradle-jcenter-push.gradle | 11 + library/gradle-mvn-push.gradle | 125 +++ library/gradle.properties | 22 + library/proguard-rules.txt | 17 + library/src/main/AndroidManifest.xml | 2 + .../itemanimators/AlphaInAnimator.java | 7 + .../itemanimators/BaseItemAnimator.java | 762 ++++++++++++++++++ .../itemanimators/BaseScaleAnimator.java | 52 ++ .../itemanimators/DefaultAnimator.java | 47 ++ .../itemanimators/ScaleUpAnimator.java | 60 ++ .../itemanimators/ScaleXAnimator.java | 57 ++ .../itemanimators/ScaleYAnimator.java | 57 ++ .../itemanimators/SlideDownAlphaAnimator.java | 49 ++ .../itemanimators/SlideLeftAlphaAnimator.java | 49 ++ .../SlideRightAlphaAnimator.java | 49 ++ .../itemanimators/SlideUpAlphaAnimator.java | 49 ++ .../values/library_itemanimators_strings.xml | 21 + settings.gradle | 2 + 59 files changed, 3385 insertions(+), 2 deletions(-) create mode 100644 DEV/ic_launcher/res/drawable-hdpi/ic_launcher.png create mode 100644 DEV/ic_launcher/res/drawable-mdpi/ic_launcher.png create mode 100644 DEV/ic_launcher/res/drawable-xhdpi/ic_launcher.png create mode 100644 DEV/ic_launcher/res/drawable-xxhdpi/ic_launcher.png create mode 100644 DEV/ic_launcher/res/drawable-xxxhdpi/ic_launcher.png create mode 100644 DEV/ic_launcher/web_hi_res_512.png create mode 100644 DEV/original/DefaultItemAnimator.java create mode 100644 app/.gitignore create mode 100644 app/build.gradle create mode 100644 app/proguard-rules.pro create mode 100644 app/src/main/AndroidManifest.xml create mode 100755 app/src/main/java/com/mikepenz/itemanimators/app/SampleActivity.java create mode 100644 app/src/main/java/com/mikepenz/itemanimators/app/dummy/ImageDummyData.java create mode 100644 app/src/main/java/com/mikepenz/itemanimators/app/items/ImageItem.java create mode 100644 app/src/main/java/com/mikepenz/itemanimators/app/items/SampleItem.java create mode 100644 app/src/main/res/anim/alpha_on.xml create mode 100644 app/src/main/res/drawable-hdpi/ic_launcher.png create mode 100644 app/src/main/res/drawable-mdpi/ic_launcher.png create mode 100644 app/src/main/res/drawable-xhdpi/ic_launcher.png create mode 100644 app/src/main/res/drawable-xxhdpi/ic_launcher.png create mode 100644 app/src/main/res/drawable-xxxhdpi/ic_launcher.png create mode 100644 app/src/main/res/drawable/gradient.xml create mode 100755 app/src/main/res/layout/activity_sample.xml create mode 100644 app/src/main/res/layout/image_item.xml create mode 100755 app/src/main/res/layout/sample_item.xml create mode 100644 app/src/main/res/menu/menu.xml create mode 100644 app/src/main/res/values/colors.xml create mode 100644 app/src/main/res/values/ids.xml create mode 100644 app/src/main/res/values/integers.xml create mode 100644 app/src/main/res/values/strings.xml create mode 100644 build.gradle create mode 100644 gradle.properties create mode 100644 gradle/wrapper/gradle-wrapper.jar create mode 100644 gradle/wrapper/gradle-wrapper.properties create mode 100755 gradlew create mode 100644 gradlew.bat create mode 100644 library/.gitignore create mode 100644 library/build.gradle create mode 100644 library/gradle-jcenter-push.gradle create mode 100644 library/gradle-mvn-push.gradle create mode 100755 library/gradle.properties create mode 100644 library/proguard-rules.txt create mode 100644 library/src/main/AndroidManifest.xml create mode 100644 library/src/main/java/com/mikepenz/itemanimators/AlphaInAnimator.java create mode 100644 library/src/main/java/com/mikepenz/itemanimators/BaseItemAnimator.java create mode 100644 library/src/main/java/com/mikepenz/itemanimators/BaseScaleAnimator.java create mode 100644 library/src/main/java/com/mikepenz/itemanimators/DefaultAnimator.java create mode 100644 library/src/main/java/com/mikepenz/itemanimators/ScaleUpAnimator.java create mode 100644 library/src/main/java/com/mikepenz/itemanimators/ScaleXAnimator.java create mode 100644 library/src/main/java/com/mikepenz/itemanimators/ScaleYAnimator.java create mode 100644 library/src/main/java/com/mikepenz/itemanimators/SlideDownAlphaAnimator.java create mode 100644 library/src/main/java/com/mikepenz/itemanimators/SlideLeftAlphaAnimator.java create mode 100644 library/src/main/java/com/mikepenz/itemanimators/SlideRightAlphaAnimator.java create mode 100644 library/src/main/java/com/mikepenz/itemanimators/SlideUpAlphaAnimator.java create mode 100755 library/src/main/res/values/library_itemanimators_strings.xml create mode 100644 settings.gradle diff --git a/.gitignore b/.gitignore index ccf2efe..1286e42 100644 --- a/.gitignore +++ b/.gitignore @@ -25,3 +25,7 @@ proguard/ # Log Files *.log + +#IntelliJ files +*.iml +.idea/ diff --git a/DEV/ic_launcher/res/drawable-hdpi/ic_launcher.png b/DEV/ic_launcher/res/drawable-hdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..a732bf4522ae509ed92dc84b850b964b89554018 GIT binary patch literal 1737 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 literal 0 HcmV?d00001 diff --git a/DEV/ic_launcher/web_hi_res_512.png b/DEV/ic_launcher/web_hi_res_512.png new file mode 100644 index 0000000000000000000000000000000000000000..38701c95747c78aa5b0d613a86484b7a990713db GIT binary patch literal 18882 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 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<>(); + + private ArrayList mAddAnimations = new ArrayList<>(); + private ArrayList mMoveAnimations = new ArrayList<>(); + private ArrayList mRemoveAnimations = new ArrayList<>(); + private ArrayList mChangeAnimations = new ArrayList<>(); + + 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 + + '}'; + } + } + + @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) { + animateRemoveImpl(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() { + for (MoveInfo moveInfo : moves) { + animateMoveImpl(moveInfo.holder, moveInfo.fromX, moveInfo.fromY, + moveInfo.toX, moveInfo.toY); + } + moves.clear(); + mMovesList.remove(moves); + } + }; + 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() { + for (ChangeInfo change : changes) { + animateChangeImpl(change); + } + changes.clear(); + mChangesList.remove(changes); + } + }; + 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() { + for (ViewHolder holder : additions) { + animateAddImpl(holder); + } + additions.clear(); + mAdditionsList.remove(additions); + } + }; + 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(); + } + } + } + + @Override + public boolean animateRemove(final ViewHolder holder) { + resetAnimation(holder); + mPendingRemovals.add(holder); + return true; + } + + private void animateRemoveImpl(final ViewHolder holder) { + final View view = holder.itemView; + final ViewPropertyAnimatorCompat animation = ViewCompat.animate(view); + mRemoveAnimations.add(holder); + animation.setDuration(getRemoveDuration()) + .alpha(0).setListener(new VpaListenerAdapter() { + @Override + public void onAnimationStart(View view) { + dispatchRemoveStarting(holder); + } + + @Override + public void onAnimationEnd(View view) { + animation.setListener(null); + ViewCompat.setAlpha(view, 1); + dispatchRemoveFinished(holder); + mRemoveAnimations.remove(holder); + dispatchFinishedWhenDone(); + } + }).start(); + } + + @Override + public boolean animateAdd(final ViewHolder holder) { + resetAnimation(holder); + ViewCompat.setAlpha(holder.itemView, 0); + mPendingAdditions.add(holder); + return true; + } + + private void animateAddImpl(final ViewHolder holder) { + final View view = holder.itemView; + final ViewPropertyAnimatorCompat animation = ViewCompat.animate(view); + mAddAnimations.add(holder); + animation.alpha(1).setDuration(getAddDuration()). + 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 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); + resetAnimation(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. + final ViewPropertyAnimatorCompat animation = ViewCompat.animate(view); + mMoveAnimations.add(holder); + 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); + resetAnimation(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) { + // carry over translation values + resetAnimation(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) { + final ViewPropertyAnimatorCompat oldViewAnim = ViewCompat.animate(view).setDuration( + getChangeDuration()); + mChangeAnimations.add(changeInfo.oldHolder); + 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) { + final ViewPropertyAnimatorCompat newViewAnimation = ViewCompat.animate(newView); + mChangeAnimations.add(changeInfo.newHolder); + 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)) { + ViewCompat.setAlpha(view, 1); + dispatchRemoveFinished(item); + } + if (mPendingAdditions.remove(item)) { + ViewCompat.setAlpha(view, 1); + 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)) { + ViewCompat.setAlpha(view, 1); + dispatchAddFinished(item); + if (additions.isEmpty()) { + mAdditionsList.remove(i); + } + } + } + + // animations should be ended by the cancel above. + //noinspection PointlessBooleanExpression,ConstantConditions + if (mRemoveAnimations.remove(item) && DEBUG) { + throw new IllegalStateException("after animation is cancelled, item should not be in " + + "mRemoveAnimations list"); + } + + //noinspection PointlessBooleanExpression,ConstantConditions + if (mAddAnimations.remove(item) && DEBUG) { + throw new IllegalStateException("after animation is cancelled, item should not be in " + + "mAddAnimations list"); + } + + //noinspection PointlessBooleanExpression,ConstantConditions + if (mChangeAnimations.remove(item) && DEBUG) { + throw new IllegalStateException("after animation is cancelled, item should not be in " + + "mChangeAnimations list"); + } + + //noinspection PointlessBooleanExpression,ConstantConditions + if (mMoveAnimations.remove(item) && DEBUG) { + throw new IllegalStateException("after animation is cancelled, item should not be in " + + "mMoveAnimations list"); + } + dispatchFinishedWhenDone(); + } + + private void resetAnimation(ViewHolder holder) { + AnimatorCompatHelper.clearInterpolator(holder.itemView); + endAnimation(holder); + } + + @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 {@link #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); + View view = item.itemView; + ViewCompat.setAlpha(view, 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 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); + 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) {} + } +} diff --git a/LICENSE b/LICENSE index 8dada3e..8f71f43 100644 --- a/LICENSE +++ b/LICENSE @@ -199,3 +199,4 @@ 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. + diff --git a/README.md b/README.md index 2703f6b..3b73b99 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,56 @@ -# ItemAnimators -ItemAnimators: Supercharged Animators for your RecyclerView +#itemanimators [![Maven Central](https://maven-badges.herokuapp.com/maven-central/com.mikepenz/itemanimators/badge.svg?style=flat)](https://maven-badges.herokuapp.com/maven-central/com.mikepenz/itemanimators) [![Join the chat at https://gitter.im/mikepenz/itemanimators](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/mikepenz/itemanimators?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) + +The **ItemAnimators** library comes with a huge collections of pre-created Animators for your RecyclerView. +It was created so developers can easly animate their RecyclerView. It also takes care about correctly handling all view states so you don't have to. + +> **DISCLAIMER**: this library does not animate items on scroll, just when added, removed, moved, or changed + +#Preview +##Screenshots + +#Include in your project +##Using Maven +```javascript +compile('com.mikepenz:itemanimators:0.0.1-SNAPSHOT@aar') { + transitive = true +} + +//only on the SNAPSHOT repo right now: +repositories { + maven { url "https://oss.sonatype.org/content/repositories/snapshots/" } +} +``` + +##How to use +```java +//just provide the animator to your RecyclerView +mRecyclerView.setItemAnimator(new ScaleUpAnimator()); + +//now it will automatically take care of all animations when you add, remove, chanage, move items +//It is very important that you use the correct notify methods if items were changed, otherwise the adapter can't animate the items +//Read more: http://developer.android.com/reference/android/support/v7/widget/RecyclerView.Adapter.html#notifyDataSetChanged() +//If you want those things out of the box have a look at the **FastAdapter** it handles everything correctly for you +//https://github.com/mikepenz/FastAdapter +``` + +#Developed By + +* Mike Penz + * [mikepenz.com](http://mikepenz.com) - + * [paypal.me/mikepenz](http://paypal.me/mikepenz) + +#License + + Copyright 2016 Mike Penz + + 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. diff --git a/app/.gitignore b/app/.gitignore new file mode 100644 index 0000000..796b96d --- /dev/null +++ b/app/.gitignore @@ -0,0 +1 @@ +/build diff --git a/app/build.gradle b/app/build.gradle new file mode 100644 index 0000000..d662f29 --- /dev/null +++ b/app/build.gradle @@ -0,0 +1,74 @@ +apply plugin: 'com.android.application' +//wrap with try and catch so the build is working even if the signing stuff is missing +try { + apply from: '../../../signing.gradle' +} catch (ex) { +} + +android { + compileSdkVersion rootProject.ext.compileSdkVersion + buildToolsVersion rootProject.ext.buildToolsVersion + + defaultConfig { + minSdkVersion 11 + targetSdkVersion 23 + versionCode 1 + versionName '0.0.1-SNAPSHOT' + + applicationVariants.all { variant -> + variant.outputs.each { output -> + def file = output.outputFile + def fileName = file.name.replace(".apk", "-v" + versionName + "-c" + versionCode + ".apk") + output.outputFile = new File(file.parentFile, fileName) + } + } + } + buildTypes { + debug { + applicationIdSuffix ".debug" + versionNameSuffix "-DEBUG" + try { + signingConfig signingConfigs.debug + } catch (ex) { + } + minifyEnabled false + } + release { + try { + signingConfig signingConfigs.release + } catch (ex) { + } + zipAlignEnabled true + minifyEnabled false + } + } + lintOptions { + abortOnError false + } +} + +dependencies { + compile project(':library') + + //used to generate the drawer on the left + //https://github.com/mikepenz/MaterialDrawer + compile('com.mikepenz:materialdrawer:5.0.0.fastAdapter.b5-SNAPSHOT@aar') { + transitive = true + exclude module: "itemanimators" + } + //used to generate the Open Source section + //https://github.com/mikepenz/AboutLibraries + compile('com.mikepenz:aboutlibraries:5.3.4@aar') { + transitive = true + } + //used to display the icons in the drawer + //https://github.com/mikepenz/Android-Iconics + compile 'com.mikepenz:material-design-iconic-typeface:2.2.0.1@aar' + + //https://github.com/JakeWharton/butterknife + compile 'com.jakewharton:butterknife:7.0.1' + + //used to load the images in the ImageListSample + //https://github.com/bumptech/glide + compile 'com.github.bumptech.glide:glide:3.6.1' +} diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro new file mode 100644 index 0000000..2ecd411 --- /dev/null +++ b/app/proguard-rules.pro @@ -0,0 +1,17 @@ +# Add project specific ProGuard rules here. +# By default, the flags in this file are appended to flags specified +# in /Entwicklung/android-sdk/tools/proguard/proguard-android.txt +# You can edit the include path and order by changing the proguardFiles +# directive in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# Add any project specific keep options here: + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml new file mode 100644 index 0000000..443c1d2 --- /dev/null +++ b/app/src/main/AndroidManifest.xml @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + diff --git a/app/src/main/java/com/mikepenz/itemanimators/app/SampleActivity.java b/app/src/main/java/com/mikepenz/itemanimators/app/SampleActivity.java new file mode 100755 index 0000000..4462a9a --- /dev/null +++ b/app/src/main/java/com/mikepenz/itemanimators/app/SampleActivity.java @@ -0,0 +1,242 @@ +package com.mikepenz.itemanimators.app; + +import android.content.Intent; +import android.graphics.Color; +import android.os.Bundle; +import android.support.v7.app.AppCompatActivity; +import android.support.v7.widget.GridLayoutManager; +import android.support.v7.widget.LinearLayoutManager; +import android.support.v7.widget.RecyclerView; +import android.support.v7.widget.Toolbar; +import android.view.Menu; +import android.view.MenuInflater; +import android.view.MenuItem; +import android.view.View; +import android.widget.AdapterView; +import android.widget.ArrayAdapter; +import android.widget.Spinner; + +import com.mikepenz.aboutlibraries.Libs; +import com.mikepenz.aboutlibraries.LibsBuilder; +import com.mikepenz.fastadapter.FastAdapter; +import com.mikepenz.fastadapter.IItem; +import com.mikepenz.fastadapter.adapters.ItemAdapter; +import com.mikepenz.iconics.IconicsDrawable; +import com.mikepenz.itemanimators.AlphaInAnimator; +import com.mikepenz.itemanimators.BaseItemAnimator; +import com.mikepenz.itemanimators.ScaleUpAnimator; +import com.mikepenz.itemanimators.ScaleXAnimator; +import com.mikepenz.itemanimators.ScaleYAnimator; +import com.mikepenz.itemanimators.SlideDownAlphaAnimator; +import com.mikepenz.itemanimators.SlideLeftAlphaAnimator; +import com.mikepenz.itemanimators.SlideRightAlphaAnimator; +import com.mikepenz.itemanimators.SlideUpAlphaAnimator; +import com.mikepenz.itemanimators.app.dummy.ImageDummyData; +import com.mikepenz.itemanimators.app.items.ImageItem; +import com.mikepenz.material_design_iconic_typeface_library.MaterialDesignIconic; +import com.mikepenz.materialdrawer.Drawer; +import com.mikepenz.materialdrawer.DrawerBuilder; +import com.mikepenz.materialdrawer.model.DividerDrawerItem; +import com.mikepenz.materialdrawer.model.PrimaryDrawerItem; +import com.mikepenz.materialdrawer.model.interfaces.IDrawerItem; + +import java.util.List; + +public class SampleActivity extends AppCompatActivity { + enum Type { + FadeIn(new AlphaInAnimator()), + ScaleUp(new ScaleUpAnimator()), + ScaleX(new ScaleXAnimator()), + ScaleY(new ScaleYAnimator()), + SlideDownAlpha(new SlideDownAlphaAnimator()), + SlideLeftAlpha(new SlideLeftAlphaAnimator()), + SlideRightAlpha(new SlideRightAlphaAnimator()), + SlideUpAlpha(new SlideUpAlphaAnimator()); + + private BaseItemAnimator mAnimator; + + Type(BaseItemAnimator animator) { + mAnimator = animator; + } + + public BaseItemAnimator getAnimator() { + return mAnimator; + } + } + + //save our header or result + private Drawer mResult = null; + //our rv + RecyclerView mRecyclerView; + //save our FastAdapter + private FastAdapter mFastAdapter; + //save our FastAdapter + private ItemAdapter mItemAdapter; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_sample); + + //improve ui + findViewById(android.R.id.content).setSystemUiVisibility(findViewById(android.R.id.content).getSystemUiVisibility() | View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR); + + // Handle Toolbar + Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar); + setSupportActionBar(toolbar); + getSupportActionBar().setTitle(""); + + //Create the drawer + mResult = new DrawerBuilder() + .withActivity(this) + .withToolbar(toolbar) + .withHasStableIds(true) + .withSavedInstance(savedInstanceState) + .withShowDrawerOnFirstLaunch(true) + .addDrawerItems( + new DividerDrawerItem(), + new PrimaryDrawerItem().withName(R.string.open_source).withSelectable(false).withIdentifier(100).withIcon(MaterialDesignIconic.Icon.gmi_github) + ) + .withOnDrawerItemClickListener(new Drawer.OnDrawerItemClickListener() { + @Override + public boolean onItemClick(View view, int position, IDrawerItem drawerItem) { + if (drawerItem != null) { + Intent intent = null; + if (drawerItem.getIdentifier() == 100) { + intent = new LibsBuilder() + .withFields(R.string.class.getFields()) + .withActivityTitle(getString(R.string.open_source)) + .withActivityStyle(Libs.ActivityStyle.LIGHT) + .intent(SampleActivity.this); + } + if (intent != null) { + SampleActivity.this.startActivity(intent); + } + } + return false; + } + }) + .build(); + + //create our FastAdapter which will manage everything + mFastAdapter = new FastAdapter(); + mFastAdapter.withMultiSelect(true); + mFastAdapter.withMultiSelectOnLongClick(false); + //create our ItemAdapter which will host our items + mItemAdapter = new ItemAdapter(); + + //configure our fastAdapter + //get our recyclerView and do basic setup + mRecyclerView = (RecyclerView) findViewById(R.id.rv); + mRecyclerView.setLayoutManager(new LinearLayoutManager(this)); + mRecyclerView.setItemAnimator(new ScaleUpAnimator()); + mRecyclerView.setAdapter(mItemAdapter.wrap(mFastAdapter)); + + //add some dummy data + mItemAdapter.add(ImageDummyData.getImages()); + + //restore selections (this has to be done after the items were added + mFastAdapter.withSavedInstanceState(savedInstanceState); + + + /** + * selection spinner for the different animtors + */ + Spinner spinner = (Spinner) findViewById(R.id.spinner_nav); + ArrayAdapter spinnerAdapter = new ArrayAdapter<>(this, android.R.layout.simple_list_item_1); + for (Type type : Type.values()) { + spinnerAdapter.add(type.name()); + } + spinner.setAdapter(spinnerAdapter); + spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() { + @Override + public void onItemSelected(AdapterView parent, View view, int position, long id) { + mRecyclerView.setItemAnimator(Type.values()[position].getAnimator()); + mRecyclerView.getItemAnimator().setAddDuration(500); + mRecyclerView.getItemAnimator().setRemoveDuration(500); + } + + @Override + public void onNothingSelected(AdapterView parent) { + } + }); + } + + @Override + public boolean onCreateOptionsMenu(Menu menu) { + MenuInflater inflater = getMenuInflater(); + inflater.inflate(R.menu.menu, menu); + menu.findItem(R.id.item_add).setIcon(new IconicsDrawable(this, MaterialDesignIconic.Icon.gmi_plus_square).color(Color.BLACK).actionBar()); + menu.findItem(R.id.item_delete).setIcon(new IconicsDrawable(this, MaterialDesignIconic.Icon.gmi_minus_square).color(Color.BLACK).actionBar()); + menu.findItem(R.id.item_change).setIcon(new IconicsDrawable(this, MaterialDesignIconic.Icon.gmi_settings_square).color(Color.BLACK).actionBar()); + menu.findItem(R.id.item_move).setIcon(new IconicsDrawable(this, MaterialDesignIconic.Icon.gmi_format_valign_bottom).color(Color.BLACK).actionBar()); + return true; + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + //find out the current visible position + int position = 0; + if (mRecyclerView.getLayoutManager() instanceof LinearLayoutManager) { + position = ((LinearLayoutManager) mRecyclerView.getLayoutManager()).findFirstVisibleItemPosition(); + } else if (mRecyclerView.getLayoutManager() instanceof GridLayoutManager) { + position = ((GridLayoutManager) mRecyclerView.getLayoutManager()).findFirstVisibleItemPosition(); + } + + //handle the menu item click + switch (item.getItemId()) { + case R.id.item_add: + if (mRecyclerView.getLayoutManager() instanceof LinearLayoutManager) { + position = ((LinearLayoutManager) mRecyclerView.getLayoutManager()).findFirstVisibleItemPosition(); + } else if (mRecyclerView.getLayoutManager() instanceof GridLayoutManager) { + position = ((GridLayoutManager) mRecyclerView.getLayoutManager()).findFirstVisibleItemPosition(); + } + mItemAdapter.add(position + 1, ImageDummyData.getDummyItem()); + return true; + case R.id.item_change: + for (Integer pos : (Iterable) mFastAdapter.getSelections()) { + ImageItem i = (ImageItem) mItemAdapter.getItem(pos); + i.withName("CHANGED"); + i.withDescription("This item was modified"); + mItemAdapter.set(pos, i); + } + return true; + case R.id.item_move: + List items = mItemAdapter.getAdapterItems(); + if (items.size() > position + 3) { + IItem i = (IItem) items.get(position + 1); + items.remove(position + 1); + items.add(position + 3, i); + mFastAdapter.notifyAdapterItemMoved(position + 1, position + 3); + } + return true; + case R.id.item_delete: + mFastAdapter.deleteAllSelectedItems(); + return true; + case android.R.id.home: + onBackPressed(); + return true; + default: + return super.onOptionsItemSelected(item); + } + } + + @Override + protected void onSaveInstanceState(Bundle outState) { + //add the values which need to be saved from the drawer to the bundle + outState = mResult.saveInstanceState(outState); + //add the values which need to be saved from the adapter to the bundel + outState = mFastAdapter.saveInstanceState(outState); + super.onSaveInstanceState(outState); + } + + @Override + public void onBackPressed() { + //handle the back press :D close the drawer first and if the drawer is closed close the activity + if (mResult != null && mResult.isDrawerOpen()) { + mResult.closeDrawer(); + } else { + super.onBackPressed(); + } + } +} diff --git a/app/src/main/java/com/mikepenz/itemanimators/app/dummy/ImageDummyData.java b/app/src/main/java/com/mikepenz/itemanimators/app/dummy/ImageDummyData.java new file mode 100644 index 0000000..83a7b63 --- /dev/null +++ b/app/src/main/java/com/mikepenz/itemanimators/app/dummy/ImageDummyData.java @@ -0,0 +1,66 @@ +package com.mikepenz.itemanimators.app.dummy; + + +import com.mikepenz.itemanimators.app.items.ImageItem; + +import java.util.Arrays; +import java.util.List; +import java.util.Random; + +/** + * Created by mikepenz on 08.01.16. + */ +public class ImageDummyData { + + public static ImageItem getDummyItem() { + int ran = new Random().nextInt(3); + if (ran == 0) { + return new ImageItem().withName("NEW").withDescription("Newly added item").withImage("https://raw.githubusercontent.com/mikepenz/earthview-wallpapers/develop/thumb/yang_zhuo_yong_cuo,_tibet-china-63.jpg"); + } else if (ran == 1) { + return new ImageItem().withName("NEW").withDescription("Newly added item").withImage("https://raw.githubusercontent.com/mikepenz/earthview-wallpapers/develop/thumb/yellowstone-united_states-17.jpg"); + } else { + return new ImageItem().withName("NEW").withDescription("Newly added item").withImage("https://raw.githubusercontent.com/mikepenz/earthview-wallpapers/develop/thumb/victoria-australia-31.jpg"); + } + } + + public static List getImages() { + return toList( + new ImageItem().withName("Yang Zhuo Yong Cuo, Tibet China").withDescription("#100063").withImage("https://raw.githubusercontent.com/mikepenz/earthview-wallpapers/develop/thumb/yang_zhuo_yong_cuo,_tibet-china-63.jpg"), + new ImageItem().withName("Yellowstone United States").withDescription("#100017").withImage("https://raw.githubusercontent.com/mikepenz/earthview-wallpapers/develop/thumb/yellowstone-united_states-17.jpg"), + new ImageItem().withName("Victoria Australia").withDescription("#100031").withImage("https://raw.githubusercontent.com/mikepenz/earthview-wallpapers/develop/thumb/victoria-australia-31.jpg"), + new ImageItem().withName("Valencia Spain").withDescription("#100082").withImage("https://raw.githubusercontent.com/mikepenz/earthview-wallpapers/develop/thumb/valencia-spain-82.jpg"), + new ImageItem().withName("Xigaze, Tibet China").withDescription("#100030").withImage("https://raw.githubusercontent.com/mikepenz/earthview-wallpapers/develop/thumb/xigaze,_tibet-china-30.jpg"), + new ImageItem().withName("Utah United States").withDescription("#100096").withImage("https://raw.githubusercontent.com/mikepenz/earthview-wallpapers/develop/thumb/utah-united_states-96.jpg"), + new ImageItem().withName("Utah United States").withDescription("#100015").withImage("https://raw.githubusercontent.com/mikepenz/earthview-wallpapers/develop/thumb/utah-united_states-15.jpg"), + new ImageItem().withName("Utah United States").withDescription("#100088").withImage("https://raw.githubusercontent.com/mikepenz/earthview-wallpapers/develop/thumb/utah-united_states-88.jpg"), + new ImageItem().withName("Umm Al Quwain United Arab Emirates").withDescription("#100013").withImage("https://raw.githubusercontent.com/mikepenz/earthview-wallpapers/develop/thumb/umm_al_quwain-united_arab_emirates-13.jpg"), + new ImageItem().withName("Texas United States").withDescription("#100026").withImage("https://raw.githubusercontent.com/mikepenz/earthview-wallpapers/develop/thumb/texas-united_states-26.jpg"), + new ImageItem().withName("Siuslaw National Forest United States").withDescription("#100092").withImage("https://raw.githubusercontent.com/mikepenz/earthview-wallpapers/develop/thumb/siuslaw_national_forest-united_states-92.jpg"), + new ImageItem().withName("The Minquiers Channel Islands").withDescription("#100069").withImage("https://raw.githubusercontent.com/mikepenz/earthview-wallpapers/develop/thumb/the_minquiers-channel_islands-69.jpg"), + new ImageItem().withName("Texas United States").withDescription("#100084").withImage("https://raw.githubusercontent.com/mikepenz/earthview-wallpapers/develop/thumb/texas-united_states-84.jpg"), + new ImageItem().withName("Tabuaeran Kiribati").withDescription("#100050").withImage("https://raw.githubusercontent.com/mikepenz/earthview-wallpapers/develop/thumb/tabuaeran-kiribati-50.jpg"), + new ImageItem().withName("Stanislaus River United States").withDescription("#100061").withImage("https://raw.githubusercontent.com/mikepenz/earthview-wallpapers/develop/thumb/stanislaus_river-united_states-61.jpg"), + new ImageItem().withName("S?ehitkamil Turkey").withDescription("#100072").withImage("https://raw.githubusercontent.com/mikepenz/earthview-wallpapers/develop/thumb/s?ehitkamil-turkey-72.jpg"), + new ImageItem().withName("Salinas Grandes Argentina").withDescription("#100025").withImage("https://raw.githubusercontent.com/mikepenz/earthview-wallpapers/develop/thumb/salinas_grandes-argentina-25.jpg"), + new ImageItem().withName("Shadegan Refuge Iran").withDescription("#100012").withImage("https://raw.githubusercontent.com/mikepenz/earthview-wallpapers/develop/thumb/shadegan_refuge-iran-12.jpg"), + new ImageItem().withName("San Pedro De Atacama Chile").withDescription("#100043").withImage("https://raw.githubusercontent.com/mikepenz/earthview-wallpapers/develop/thumb/san_pedro_de_atacama-chile-43.jpg"), + new ImageItem().withName("Ragged Island The Bahamas").withDescription("#100064").withImage("https://raw.githubusercontent.com/mikepenz/earthview-wallpapers/develop/thumb/ragged_island-the_bahamas-64.jpg"), + new ImageItem().withName("Qinghai Lake China").withDescription("#100080").withImage("https://raw.githubusercontent.com/mikepenz/earthview-wallpapers/develop/thumb/qinghai_lake-china-80.jpg"), + new ImageItem().withName("Qesm Al Wahat Ad Dakhlah Egypt").withDescription("#100056").withImage("https://raw.githubusercontent.com/mikepenz/earthview-wallpapers/develop/thumb/qesm_al_wahat_ad_dakhlah-egypt-56.jpg"), + new ImageItem().withName("Riedstadt Germany").withDescription("#100042").withImage("https://raw.githubusercontent.com/mikepenz/earthview-wallpapers/develop/thumb/riedstadt-germany-42.jpg"), + new ImageItem().withName("Redwood City United States").withDescription("#100048").withImage("https://raw.githubusercontent.com/mikepenz/earthview-wallpapers/develop/thumb/redwood_city-united_states-48.jpg"), + new ImageItem().withName("Nyingchi, Tibet China").withDescription("#100098").withImage("https://raw.githubusercontent.com/mikepenz/earthview-wallpapers/develop/thumb/nyingchi,_tibet-china-98.jpg"), + new ImageItem().withName("Ngari, Tibet China").withDescription("#100057").withImage("https://raw.githubusercontent.com/mikepenz/earthview-wallpapers/develop/thumb/ngari,_tibet-china-57.jpg"), + new ImageItem().withName("Pozoantiguo Spain").withDescription("#100099").withImage("https://raw.githubusercontent.com/mikepenz/earthview-wallpapers/develop/thumb/pozoantiguo-spain-99.jpg"), + new ImageItem().withName("Ningaloo Australia").withDescription("#100073").withImage("https://raw.githubusercontent.com/mikepenz/earthview-wallpapers/develop/thumb/ningaloo-australia-73.jpg"), + new ImageItem().withName("Niederzier Germany").withDescription("#100079").withImage("https://raw.githubusercontent.com/mikepenz/earthview-wallpapers/develop/thumb/niederzier-germany-79.jpg"), + new ImageItem().withName("Olympic Dam Australia").withDescription("#100065").withImage("https://raw.githubusercontent.com/mikepenz/earthview-wallpapers/develop/thumb/olympic_dam-australia-65.jpg"), + new ImageItem().withName("Peedamulla Australia").withDescription("#100040").withImage("https://raw.githubusercontent.com/mikepenz/earthview-wallpapers/develop/thumb/peedamulla-australia-40.jpg"), + new ImageItem().withName("Nevado Tres Cruces Park Chile").withDescription("#100089").withImage("https://raw.githubusercontent.com/mikepenz/earthview-wallpapers/develop/thumb/nevado_tres_cruces_park-chile-89.jpg") + ); + } + + private static List toList(ImageItem... imageItems) { + return Arrays.asList(imageItems); + } +} diff --git a/app/src/main/java/com/mikepenz/itemanimators/app/items/ImageItem.java b/app/src/main/java/com/mikepenz/itemanimators/app/items/ImageItem.java new file mode 100644 index 0000000..d5fcbfd --- /dev/null +++ b/app/src/main/java/com/mikepenz/itemanimators/app/items/ImageItem.java @@ -0,0 +1,132 @@ +package com.mikepenz.itemanimators.app.items; + +import android.content.Context; +import android.graphics.Color; +import android.support.v7.widget.RecyclerView; +import android.view.View; +import android.widget.FrameLayout; +import android.widget.ImageView; +import android.widget.TextView; + +import com.bumptech.glide.Glide; +import com.mikepenz.fastadapter.items.AbstractItem; +import com.mikepenz.fastadapter.utils.FastAdapterUIUtils; +import com.mikepenz.fastadapter.utils.ViewHolderFactory; +import com.mikepenz.itemanimators.app.R; +import com.mikepenz.materialize.util.UIUtils; + +import butterknife.Bind; +import butterknife.ButterKnife; + +/** + * Created by mikepenz on 28.12.15. + */ +public class ImageItem extends AbstractItem { + + public String mImageUrl; + public String mName; + public String mDescription; + + public ImageItem withImage(String imageUrl) { + this.mImageUrl = imageUrl; + return this; + } + + public ImageItem withName(String name) { + this.mName = name; + return this; + } + + public ImageItem withDescription(String description) { + this.mDescription = description; + return this; + } + + @Override + public int getType() { + return R.id.fastadapter_image_item_id; + } + + @Override + public int getLayoutRes() { + return R.layout.image_item; + } + + @Override + public void bindView(RecyclerView.ViewHolder holder) { + Context ctx = holder.itemView.getContext(); + //get our viewHolder + final ViewHolder viewHolder = (ViewHolder) holder; + + //set the item selected if it is + viewHolder.itemView.setSelected(isSelected()); + //set itself as tag. (not required) + viewHolder.itemView.setTag(this); + + //define our data for the view + viewHolder.imageName.setText(mName); + viewHolder.imageDescription.setText(mDescription); + viewHolder.imageView.setImageBitmap(null); + + //set the background for the item + int color = UIUtils.getThemeColor(ctx, R.attr.colorPrimary); + viewHolder.imageContent.setForeground(FastAdapterUIUtils.getSelectableBackground(ctx, Color.argb(100, Color.red(color), Color.green(color), Color.blue(color)))); + + //load glide + Glide.clear(viewHolder.imageView); + Glide.with(ctx).load(mImageUrl).animate(R.anim.alpha_on).into(viewHolder.imageView); + } + + /** + * our ItemFactory implementation which creates the ViewHolder for our adapter. + * It is highly recommended to implement a ViewHolderFactory as it is 0-1ms faster for ViewHolder creation, + * and it is also many many times more efficient if you define custom listeners on views within your item. + */ + public class ItemFactory implements ViewHolderFactory { + public ViewHolder create(View v) { + return new ViewHolder(v); + } + } + + /** + * return our ViewHolderFactory implementation here + * + * @return + */ + @Override + public ViewHolderFactory getFactory() { + return new ItemFactory(); + } + + /** + * our ViewHolder + */ + protected static class ViewHolder extends RecyclerView.ViewHolder { + protected View view; + @Bind(R.id.item_image_img) + protected ImageView imageView; + @Bind(R.id.item_image_name) + protected TextView imageName; + @Bind(R.id.item_image_description) + protected TextView imageDescription; + @Bind(R.id.item_image_content) + protected FrameLayout imageContent; + + public ViewHolder(View view) { + super(view); + ButterKnife.bind(this, view); + this.view = view; + + //optimization to preset the correct height for our device + int screenWidth = view.getContext().getResources().getDisplayMetrics().widthPixels; + int finalHeight = (int) (screenWidth / 1.5) / 2; + imageView.setMinimumHeight(finalHeight); + imageView.setMaxHeight(finalHeight); + imageView.setAdjustViewBounds(false); + //set height as layoutParameter too + FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) imageView.getLayoutParams(); + lp.height = finalHeight; + imageView.setLayoutParams(lp); + } + } +} diff --git a/app/src/main/java/com/mikepenz/itemanimators/app/items/SampleItem.java b/app/src/main/java/com/mikepenz/itemanimators/app/items/SampleItem.java new file mode 100644 index 0000000..7bd57b2 --- /dev/null +++ b/app/src/main/java/com/mikepenz/itemanimators/app/items/SampleItem.java @@ -0,0 +1,134 @@ +package com.mikepenz.itemanimators.app.items; + +import android.content.Context; +import android.support.annotation.StringRes; +import android.support.v7.widget.RecyclerView; +import android.view.View; +import android.widget.TextView; + +import com.mikepenz.fastadapter.ICollapsible; +import com.mikepenz.fastadapter.IItem; +import com.mikepenz.fastadapter.items.AbstractItem; +import com.mikepenz.fastadapter.utils.FastAdapterUIUtils; +import com.mikepenz.fastadapter.utils.ViewHolderFactory; +import com.mikepenz.itemanimators.app.R; +import com.mikepenz.materialdrawer.holder.StringHolder; +import com.mikepenz.materialize.util.UIUtils; + +import java.util.List; + +import butterknife.Bind; +import butterknife.ButterKnife; + +/** + * Created by mikepenz on 28.12.15. + */ +public class SampleItem extends AbstractItem implements ICollapsible { + + public String header; + public StringHolder name; + public StringHolder description; + + private List mSubItems; + private boolean mCollapsed = true; + + public SampleItem withHeader(String header) { + this.header = header; + return this; + } + + public SampleItem withName(String Name) { + this.name = new StringHolder(Name); + return this; + } + + public SampleItem withName(@StringRes int NameRes) { + this.name = new StringHolder(NameRes); + return this; + } + + public SampleItem withDescription(String description) { + this.description = new StringHolder(description); + return this; + } + + public SampleItem withDescription(@StringRes int descriptionRes) { + this.description = new StringHolder(descriptionRes); + return this; + } + + @Override + public boolean isCollapsed() { + return mCollapsed; + } + + @Override + public SampleItem withCollapsed(boolean collapsed) { + mCollapsed = collapsed; + return this; + } + + @Override + public List getSubItems() { + return mSubItems; + } + + public SampleItem withSubItems(List subItems) { + this.mSubItems = subItems; + return this; + } + + @Override + public int getType() { + return R.id.fastadapter_sampleitem_id; + } + + @Override + public int getLayoutRes() { + return R.layout.sample_item; + } + + @Override + public void bindView(RecyclerView.ViewHolder holder) { + Context ctx = holder.itemView.getContext(); + //get our viewHolder + ViewHolder viewHolder = (ViewHolder) holder; + + //set the item selected if it is + viewHolder.itemView.setSelected(isSelected()); + //set itself as tag. (not required) + viewHolder.itemView.setTag(this); + + //set the background for the item + UIUtils.setBackground(viewHolder.view, FastAdapterUIUtils.getSelectableBackground(ctx, UIUtils.getThemeColor(ctx, R.attr.colorPrimary))); + //set the text for the name + StringHolder.applyTo(name, viewHolder.name); + //set the text for the description or hide + StringHolder.applyToOrHide(description, viewHolder.description); + } + + @Override + public ViewHolderFactory getFactory() { + return new ItemFactory(); + } + + public static class ItemFactory implements ViewHolderFactory { + public ViewHolder create(View v) { + return new ViewHolder(v); + } + } + + protected static class ViewHolder extends RecyclerView.ViewHolder { + protected View view; + @Bind(R.id.material_drawer_name) + TextView name; + @Bind(R.id.material_drawer_description) + TextView description; + + public ViewHolder(View view) { + super(view); + ButterKnife.bind(this, view); + this.view = view; + } + } +} diff --git a/app/src/main/res/anim/alpha_on.xml b/app/src/main/res/anim/alpha_on.xml new file mode 100644 index 0000000..80736f8 --- /dev/null +++ b/app/src/main/res/anim/alpha_on.xml @@ -0,0 +1,6 @@ + + + \ No newline at end of file diff --git a/app/src/main/res/drawable-hdpi/ic_launcher.png b/app/src/main/res/drawable-hdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..a732bf4522ae509ed92dc84b850b964b89554018 GIT binary patch literal 1737 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 literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable/gradient.xml b/app/src/main/res/drawable/gradient.xml new file mode 100644 index 0000000..f3dd29a --- /dev/null +++ b/app/src/main/res/drawable/gradient.xml @@ -0,0 +1,10 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_sample.xml b/app/src/main/res/layout/activity_sample.xml new file mode 100755 index 0000000..321c55e --- /dev/null +++ b/app/src/main/res/layout/activity_sample.xml @@ -0,0 +1,35 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/image_item.xml b/app/src/main/res/layout/image_item.xml new file mode 100644 index 0000000..f002bb1 --- /dev/null +++ b/app/src/main/res/layout/image_item.xml @@ -0,0 +1,65 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/sample_item.xml b/app/src/main/res/layout/sample_item.xml new file mode 100755 index 0000000..f7dda3a --- /dev/null +++ b/app/src/main/res/layout/sample_item.xml @@ -0,0 +1,36 @@ + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/menu/menu.xml b/app/src/main/res/menu/menu.xml new file mode 100644 index 0000000..c5f48c8 --- /dev/null +++ b/app/src/main/res/menu/menu.xml @@ -0,0 +1,26 @@ + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml new file mode 100644 index 0000000..2816d0a --- /dev/null +++ b/app/src/main/res/values/colors.xml @@ -0,0 +1,7 @@ + + + #eeff41 + #cddc39 + #ffff00 + #ff5722 + \ No newline at end of file diff --git a/app/src/main/res/values/ids.xml b/app/src/main/res/values/ids.xml new file mode 100644 index 0000000..201248d --- /dev/null +++ b/app/src/main/res/values/ids.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/values/integers.xml b/app/src/main/res/values/integers.xml new file mode 100644 index 0000000..089a4cc --- /dev/null +++ b/app/src/main/res/values/integers.xml @@ -0,0 +1,4 @@ + + + 300 + \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml new file mode 100644 index 0000000..a461216 --- /dev/null +++ b/app/src/main/res/values/strings.xml @@ -0,0 +1,5 @@ + + ItemAnimators + + Open Source + diff --git a/build.gradle b/build.gradle new file mode 100644 index 0000000..80a914b --- /dev/null +++ b/build.gradle @@ -0,0 +1,30 @@ +// Top-level build file where you can add configuration options common to all sub-projects/modules. + +buildscript { + repositories { + jcenter() + } + dependencies { + classpath 'com.android.tools.build:gradle:2.0.0-alpha3' + classpath 'com.novoda:bintray-release:0.3.4' + } +} + +// To avoid manually setting the same values in all Android modules, set the value on the root +// project and then reference this from the modules +ext { + compileSdkVersion = 23 + buildToolsVersion = "23.0.2" + supportLibVersion = "23.1.1" +} + +allprojects { + repositories { + jcenter() + maven { url "https://oss.sonatype.org/content/repositories/snapshots/" } + } +} + +task wrapper(type: Wrapper) { + gradleVersion = '2.10' +} diff --git a/gradle.properties b/gradle.properties new file mode 100644 index 0000000..18cd624 --- /dev/null +++ b/gradle.properties @@ -0,0 +1,35 @@ +# Project-wide Gradle settings. + +# IDE (e.g. Android Studio) users: +# Settings specified in this file will override any Gradle settings +# configured through the IDE. + +# For more details on how to configure your build environment visit +# http://www.gradle.org/docs/current/userguide/build_environment.html + +# Specifies the JVM arguments used for the daemon process. +# The setting is particularly useful for tweaking memory settings. +# Default value: -Xmx10248m -XX:MaxPermSize=256m +# org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 + +# When configured, Gradle will run in incubating parallel mode. +# This option should only be used with decoupled projects. More details, visit +# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects +org.gradle.daemon=true +org.gradle.parallel=true + +# Maven stuff +VERSION_NAME=0.0.1-SNAPSHOT +VERSION_CODE=1 +GROUP=com.mikepenz + +POM_DESCRIPTION=ItemAnimators Library +POM_URL=https://github.com/mikepenz/itemanimators +POM_SCM_URL=https://github.com/mikepenz/itemanimators +POM_SCM_CONNECTION=scm:git@github.com:mikepenz/itemanimators.git +POM_SCM_DEV_CONNECTION=scm:git@github.com:mikepenz/itemanimators.git +POM_LICENCE_NAME=The Apache Software License, Version 2.0 +POM_LICENCE_URL=http://www.apache.org/licenses/LICENSE-2.0.txt +POM_LICENCE_DIST=repo +POM_DEVELOPER_ID=mikepenz +POM_DEVELOPER_NAME=Mike Penz diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000000000000000000000000000000000000..05ef575b0cd0173fc735f2857ce4bd594ce4f6bd GIT binary patch literal 53637 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 t9m@SZ!E*7&jsr?!t7TL-WYI4eM@gAug8 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 \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >/dev/null +APP_HOME="`pwd -P`" +cd "$SAVED" >/dev/null + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD="java" + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then + MAX_FD_LIMIT=`ulimit -H -n` + if [ $? -eq 0 ] ; then + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then + MAX_FD="$MAX_FD_LIMIT" + fi + ulimit -n $MAX_FD + if [ $? -ne 0 ] ; then + warn "Could not set maximum file descriptor limit: $MAX_FD" + fi + else + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" + fi +fi + +# For Darwin, add options to specify how the application appears in the dock +if $darwin; then + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" +fi + +# For Cygwin, switch paths to Windows format before running java +if $cygwin ; then + APP_HOME=`cygpath --path --mixed "$APP_HOME"` + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + JAVACMD=`cygpath --unix "$JAVACMD"` + + # We build the pattern for arguments to be converted via cygpath + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` + SEP="" + for dir in $ROOTDIRSRAW ; do + ROOTDIRS="$ROOTDIRS$SEP$dir" + SEP="|" + done + OURCYGPATTERN="(^($ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "$GRADLE_CYGPATTERN" != "" ] ; then + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" + fi + # Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 + for arg in "$@" ; do + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option + + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` + else + eval `echo args$i`="\"$arg\"" + fi + i=$((i+1)) + done + case $i in + (0) set -- ;; + (1) set -- "$args0" ;; + (2) set -- "$args0" "$args1" ;; + (3) set -- "$args0" "$args1" "$args2" ;; + (4) set -- "$args0" "$args1" "$args2" "$args3" ;; + (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + esac +fi + +# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules +function splitJvmOpts() { + JVM_OPTS=("$@") +} +eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS +JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" + +exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" diff --git a/gradlew.bat b/gradlew.bat new file mode 100644 index 0000000..aec9973 --- /dev/null +++ b/gradlew.bat @@ -0,0 +1,90 @@ +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS= + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto init + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto init + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:init +@rem Get command-line arguments, handling Windowz variants + +if not "%OS%" == "Windows_NT" goto win9xME_args +if "%@eval[2+2]" == "4" goto 4NT_args + +:win9xME_args +@rem Slurp the command line arguments. +set CMD_LINE_ARGS= +set _SKIP=2 + +:win9xME_args_slurp +if "x%~1" == "x" goto execute + +set CMD_LINE_ARGS=%* +goto execute + +:4NT_args +@rem Get arguments from the 4NT Shell from JP Software +set CMD_LINE_ARGS=%$ + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/library/.gitignore b/library/.gitignore new file mode 100644 index 0000000..796b96d --- /dev/null +++ b/library/.gitignore @@ -0,0 +1 @@ +/build diff --git a/library/build.gradle b/library/build.gradle new file mode 100644 index 0000000..2a7e9ca --- /dev/null +++ b/library/build.gradle @@ -0,0 +1,32 @@ +apply plugin: 'com.android.library' +apply plugin: 'com.novoda.bintray-release' + +android { + compileSdkVersion rootProject.ext.compileSdkVersion + buildToolsVersion rootProject.ext.buildToolsVersion + + defaultConfig { + minSdkVersion 10 + targetSdkVersion 23 + versionCode 1 + versionName '0.0.1-SNAPSHOT' + } + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt' + } + } + productFlavors { + } + lintOptions { + abortOnError false + } +} + +apply from: 'gradle-mvn-push.gradle' +apply from: 'gradle-jcenter-push.gradle' + +dependencies { + compile "com.android.support:recyclerview-v7:${rootProject.ext.supportLibVersion}" +} diff --git a/library/gradle-jcenter-push.gradle b/library/gradle-jcenter-push.gradle new file mode 100644 index 0000000..bece178 --- /dev/null +++ b/library/gradle-jcenter-push.gradle @@ -0,0 +1,11 @@ +publish { + dryRun = false + bintrayUser = project.hasProperty('bintray.user') ? project.property('bintray.user') : System.getenv('BINTRAY_USER') + bintrayKey = project.hasProperty('bintray.apikey') ? project.property('bintray.apikey') : System.getenv('BINTRAY_API_KEY') + userOrg = project.property("POM_DEVELOPER_ID") + groupId = project.property("GROUP") + artifactId = project.property("GROUP") + ":" + project.property("POM_ARTIFACT_ID") + publishVersion = project.property("VERSION_NAME") + desc = project.property("POM_DESCRIPTION") + website = project.property("POM_URL") +} \ No newline at end of file diff --git a/library/gradle-mvn-push.gradle b/library/gradle-mvn-push.gradle new file mode 100644 index 0000000..60e1c84 --- /dev/null +++ b/library/gradle-mvn-push.gradle @@ -0,0 +1,125 @@ +/* + * Copyright 2013 Chris Banes + * + * 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. + */ + +apply plugin: 'maven' +apply plugin: 'signing' + +def isReleaseBuild() { + return VERSION_NAME.contains("SNAPSHOT") == false +} + +def getReleaseRepositoryUrl() { + return hasProperty('RELEASE_REPOSITORY_URL') ? RELEASE_REPOSITORY_URL + : "https://oss.sonatype.org/service/local/staging/deploy/maven2/" +} + +def getSnapshotRepositoryUrl() { + return hasProperty('SNAPSHOT_REPOSITORY_URL') ? SNAPSHOT_REPOSITORY_URL + : "https://oss.sonatype.org/content/repositories/snapshots/" +} + +def getRepositoryUsername() { + return hasProperty('NEXUS_USERNAME') ? NEXUS_USERNAME : "" +} + +def getRepositoryPassword() { + return hasProperty('NEXUS_PASSWORD') ? NEXUS_PASSWORD : "" +} + +afterEvaluate { project -> + uploadArchives { + repositories { + mavenDeployer { + beforeDeployment { MavenDeployment deployment -> signing.signPom(deployment) } + + pom.groupId = GROUP + pom.artifactId = POM_ARTIFACT_ID + pom.version = VERSION_NAME + + repository(url: getReleaseRepositoryUrl()) { + authentication(userName: getRepositoryUsername(), password: getRepositoryPassword()) + } + snapshotRepository(url: getSnapshotRepositoryUrl()) { + authentication(userName: getRepositoryUsername(), password: getRepositoryPassword()) + } + + pom.project { + name POM_NAME + packaging POM_PACKAGING + description POM_DESCRIPTION + url POM_URL + + scm { + url POM_SCM_URL + connection POM_SCM_CONNECTION + developerConnection POM_SCM_DEV_CONNECTION + } + + licenses { + license { + name POM_LICENCE_NAME + url POM_LICENCE_URL + distribution POM_LICENCE_DIST + } + } + + developers { + developer { + id POM_DEVELOPER_ID + name POM_DEVELOPER_NAME + } + } + } + } + } + } + + signing { + required { isReleaseBuild() && gradle.taskGraph.hasTask("uploadArchives") } + sign configurations.archives + } + + android.libraryVariants.all { variant -> + def javadocTask = task("generate${variant.name.capitalize()}Javadoc", type: Javadoc) { + description "Generates Javadoc for $variant.name." + source = variant.javaCompile.source + ext.androidJar = project.files(android.getBootClasspath().join(File.pathSeparator)) + classpath = files(variant.javaCompile.classpath.files) + files(ext.androidJar) + exclude '**/BuildConfig.java' + exclude '**/R.java' + } + + javadocTask.dependsOn variant.javaCompile + + def jarJavadocTask = task("jar${variant.name.capitalize()}Javadoc", type: Jar) { + description "Generate Javadoc Jar for $variant.name" + classifier = 'javadoc' + from javadocTask.destinationDir + } + + jarJavadocTask.dependsOn javadocTask + artifacts.add('archives', jarJavadocTask) + + def jarSourceTask = task("jar${variant.name.capitalize()}Sources", type: Jar) { + description "Generates Java Sources for $variant.name." + classifier = 'sources' + from variant.javaCompile.source + } + + jarSourceTask.dependsOn variant.javaCompile + artifacts.add('archives', jarSourceTask) + } +} diff --git a/library/gradle.properties b/library/gradle.properties new file mode 100755 index 0000000..8e3ec9a --- /dev/null +++ b/library/gradle.properties @@ -0,0 +1,22 @@ +# Project-wide Gradle settings. + +# IDE (e.g. Android Studio) users: +# Settings specified in this file will override any Gradle settings +# configured through the IDE. + +# For more details on how to configure your build environment visit +# http://www.gradle.org/docs/current/userguide/build_environment.html + +# Specifies the JVM arguments used for the daemon process. +# The setting is particularly useful for tweaking memory settings. +# Default value: -Xmx10248m -XX:MaxPermSize=256m +# org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 + +# When configured, Gradle will run in incubating parallel mode. +# This option should only be used with decoupled projects. More details, visit +# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects +# org.gradle.parallel=true + +POM_NAME=itemanimators Library +POM_ARTIFACT_ID=itemanimators +POM_PACKAGING=aar diff --git a/library/proguard-rules.txt b/library/proguard-rules.txt new file mode 100644 index 0000000..9827206 --- /dev/null +++ b/library/proguard-rules.txt @@ -0,0 +1,17 @@ +# Add project specific ProGuard rules here. +# By default, the flags in this file are appended to flags specified +# in /Entwicklung/android-sdk/tools/proguard/proguard-android.txt +# You can edit the include path and order by changing the ProGuard +# include property in project.properties. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# Add any project specific keep options here: + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} \ No newline at end of file diff --git a/library/src/main/AndroidManifest.xml b/library/src/main/AndroidManifest.xml new file mode 100644 index 0000000..4c44df5 --- /dev/null +++ b/library/src/main/AndroidManifest.xml @@ -0,0 +1,2 @@ + + diff --git a/library/src/main/java/com/mikepenz/itemanimators/AlphaInAnimator.java b/library/src/main/java/com/mikepenz/itemanimators/AlphaInAnimator.java new file mode 100644 index 0000000..94ca547 --- /dev/null +++ b/library/src/main/java/com/mikepenz/itemanimators/AlphaInAnimator.java @@ -0,0 +1,7 @@ +package com.mikepenz.itemanimators; + +/** + * Created by mikepenz on 08.01.16. + */ +public class AlphaInAnimator extends DefaultAnimator { +} diff --git a/library/src/main/java/com/mikepenz/itemanimators/BaseItemAnimator.java b/library/src/main/java/com/mikepenz/itemanimators/BaseItemAnimator.java new file mode 100644 index 0000000..d75a370 --- /dev/null +++ b/library/src/main/java/com/mikepenz/itemanimators/BaseItemAnimator.java @@ -0,0 +1,762 @@ +/* + * 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. + */ +package com.mikepenz.itemanimators; + +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.support.v7.widget.RecyclerView.ViewHolder; +import android.support.v7.widget.SimpleItemAnimator; +import android.view.View; +import android.view.animation.Interpolator; + +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 CollapsingItemAnimator by default. + * + * @see RecyclerView#setItemAnimator(RecyclerView.ItemAnimator) + */ +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<>(); + + private ArrayList mAddAnimations = new ArrayList<>(); + private ArrayList mMoveAnimations = new ArrayList<>(); + private ArrayList mRemoveAnimations = new ArrayList<>(); + private ArrayList mChangeAnimations = new ArrayList<>(); + + Interpolator mInterpolator; + + 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; + } + } + + protected 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 + + '}'; + } + } + + /** + * defines the interpolator used for the animations + * + * @param interpolator the interpolator used for the animations + * @return the implementing class T + */ + public T withInterpolator(Interpolator interpolator) { + this.mInterpolator = interpolator; + return (T) this; + } + + /** + * @return the interpolator used for the animations + */ + public Interpolator getInterpolator() { + return this.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) { + animateRemoveImpl(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() { + for (MoveInfo moveInfo : moves) { + animateMoveImpl(moveInfo.holder, moveInfo.fromX, moveInfo.fromY, + moveInfo.toX, moveInfo.toY); + } + moves.clear(); + mMovesList.remove(moves); + } + }; + if (removalsPending) { + View view = moves.get(0).holder.itemView; + ViewCompat.postOnAnimationDelayed(view, mover, 0); + } 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() { + for (ChangeInfo change : changes) { + animateChangeImpl(change); + } + changes.clear(); + mChangesList.remove(changes); + } + }; + if (removalsPending) { + ViewHolder holder = changes.get(0).oldHolder; + + long moveDuration = movesPending ? getMoveDuration() : 0; + ViewCompat.postOnAnimationDelayed(holder.itemView, changer, getRemoveDelay(getRemoveDuration(), moveDuration, getChangeDuration())); + } 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() { + for (ViewHolder holder : additions) { + animateAddImpl(holder); + } + additions.clear(); + mAdditionsList.remove(additions); + } + }; + if (removalsPending || movesPending || changesPending) { + long removeDuration = removalsPending ? getRemoveDuration() : 0; + long moveDuration = movesPending ? getMoveDuration() : 0; + long changeDuration = changesPending ? getChangeDuration() : 0; + View view = additions.get(0).itemView; + ViewCompat.postOnAnimationDelayed(view, adder, getAddDelay(removeDuration, moveDuration, changeDuration)); + } else { + adder.run(); + } + } + } + + /** + * used to calculated the delay until the remove animation should start + * + * @param remove the remove duration + * @param move the move duration + * @param change the change duration + * @return the calculated delay for the remove items animation + */ + public long getRemoveDelay(long remove, long move, long change) { + return remove + Math.max(move, change); + } + + /** + * used to calculated the delay until the add animation should start + * + * @param remove the remove duration + * @param move the move duration + * @param change the change duration + * @return the calculated delay for the add items animation + */ + public long getAddDelay(long remove, long move, long change) { + return remove + Math.max(move, change); + } + + @Override + public boolean animateRemove(final ViewHolder holder) { + resetAnimation(holder); + mPendingRemovals.add(holder); + return true; + } + + private void animateRemoveImpl(final ViewHolder holder) { + final View view = holder.itemView; + final ViewPropertyAnimatorCompat animation = removeAnimation(view); + mRemoveAnimations.add(holder); + animation.setListener(new VpaListenerAdapter() { + @Override + public void onAnimationStart(View view) { + dispatchRemoveStarting(holder); + } + + @Override + public void onAnimationEnd(View view) { + animation.setListener(null); + removeAnimationCleanup(view); + dispatchRemoveFinished(holder); + mRemoveAnimations.remove(holder); + dispatchFinishedWhenDone(); + } + }).start(); + } + + abstract public ViewPropertyAnimatorCompat removeAnimation(View view); + + abstract public void removeAnimationCleanup(View view); + + @Override + public boolean animateAdd(final ViewHolder holder) { + resetAnimation(holder); + addAnimationPrepare(holder.itemView); + mPendingAdditions.add(holder); + return true; + } + + private void animateAddImpl(final ViewHolder holder) { + final View view = holder.itemView; + final ViewPropertyAnimatorCompat animation = addAnimation(view); + mAddAnimations.add(holder); + animation. + setListener(new VpaListenerAdapter() { + @Override + public void onAnimationStart(View view) { + dispatchAddStarting(holder); + } + + @Override + public void onAnimationCancel(View view) { + addAnimationCleanup(view); + } + + @Override + public void onAnimationEnd(View view) { + animation.setListener(null); + dispatchAddFinished(holder); + mAddAnimations.remove(holder); + dispatchFinishedWhenDone(); + } + }).start(); + } + + /** + * the animation to prepare the view before the add animation is run + * + * @param view + */ + abstract public void addAnimationPrepare(View view); + + /** + * the animation for adding a view + * + * @param view + * @return + */ + abstract public ViewPropertyAnimatorCompat addAnimation(View view); + + /** + * the cleanup method if the animation needs to be stopped. and tro prepare for the next view + * + * @param view + */ + abstract void addAnimationCleanup(View view); + + @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); + resetAnimation(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. + final ViewPropertyAnimatorCompat animation = ViewCompat.animate(view); + mMoveAnimations.add(holder); + 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); + } + changeAnimation(oldHolder, newHolder, + fromX, fromY, toX, toY); + 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) { + final ViewPropertyAnimatorCompat oldViewAnim = changeOldAnimation(view, changeInfo); + mChangeAnimations.add(changeInfo.oldHolder); + oldViewAnim.setListener(new VpaListenerAdapter() { + @Override + public void onAnimationStart(View view) { + dispatchChangeStarting(changeInfo.oldHolder, true); + } + + @Override + public void onAnimationEnd(View view) { + oldViewAnim.setListener(null); + changeAnimationCleanup(view); + ViewCompat.setTranslationX(view, 0); + ViewCompat.setTranslationY(view, 0); + dispatchChangeFinished(changeInfo.oldHolder, true); + mChangeAnimations.remove(changeInfo.oldHolder); + dispatchFinishedWhenDone(); + } + }).start(); + } + if (newView != null) { + final ViewPropertyAnimatorCompat newViewAnimation = changeNewAnimation(newView); + mChangeAnimations.add(changeInfo.newHolder); + newViewAnimation.setListener(new VpaListenerAdapter() { + @Override + public void onAnimationStart(View view) { + dispatchChangeStarting(changeInfo.newHolder, false); + } + + @Override + public void onAnimationEnd(View view) { + newViewAnimation.setListener(null); + changeAnimationCleanup(newView); + ViewCompat.setTranslationX(newView, 0); + ViewCompat.setTranslationY(newView, 0); + dispatchChangeFinished(changeInfo.newHolder, false); + mChangeAnimations.remove(changeInfo.newHolder); + dispatchFinishedWhenDone(); + } + }).start(); + } + } + + /** + * the whole change animation if we have to cross animate two views + * + * @param oldHolder + * @param newHolder + * @param fromX + * @param fromY + * @param toX + * @param toY + */ + public void changeAnimation(ViewHolder oldHolder, ViewHolder newHolder, int fromX, int fromY, int toX, int toY) { + final float prevTranslationX = ViewCompat.getTranslationX(oldHolder.itemView); + final float prevTranslationY = ViewCompat.getTranslationY(oldHolder.itemView); + final float prevValue = ViewCompat.getAlpha(oldHolder.itemView); + resetAnimation(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, prevValue); + if (newHolder != null) { + // carry over translation values + resetAnimation(newHolder); + ViewCompat.setTranslationX(newHolder.itemView, -deltaX); + ViewCompat.setTranslationY(newHolder.itemView, -deltaY); + ViewCompat.setAlpha(newHolder.itemView, 0); + } + } + + /** + * the animation for removing the old view + * + * @param view + * @return + */ + abstract public ViewPropertyAnimatorCompat changeOldAnimation(View view, ChangeInfo changeInfo); + + /** + * the animation for changing the new view + * + * @param view + * @return + */ + abstract public ViewPropertyAnimatorCompat changeNewAnimation(View view); + + /** + * the cleanup method if the animation needs to be stopped. and tro prepare for the next view + * + * @param view + */ + abstract public void changeAnimationCleanup(View view); + + 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; + } + changeAnimationCleanup(item.itemView); + 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)) { + removeAnimationCleanup(view); + dispatchRemoveFinished(item); + } + if (mPendingAdditions.remove(item)) { + addAnimationCleanup(view); + 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)) { + addAnimationCleanup(view); + dispatchAddFinished(item); + if (additions.isEmpty()) { + mAdditionsList.remove(i); + } + } + } + + // animations should be ended by the cancel above. + //noinspection PointlessBooleanExpression,ConstantConditions + if (mRemoveAnimations.remove(item) && DEBUG) { + throw new IllegalStateException("after animation is cancelled, item should not be in " + + "mRemoveAnimations list"); + } + + //noinspection PointlessBooleanExpression,ConstantConditions + if (mAddAnimations.remove(item) && DEBUG) { + throw new IllegalStateException("after animation is cancelled, item should not be in " + + "mAddAnimations list"); + } + + //noinspection PointlessBooleanExpression,ConstantConditions + if (mChangeAnimations.remove(item) && DEBUG) { + throw new IllegalStateException("after animation is cancelled, item should not be in " + + "mChangeAnimations list"); + } + + //noinspection PointlessBooleanExpression,ConstantConditions + if (mMoveAnimations.remove(item) && DEBUG) { + throw new IllegalStateException("after animation is cancelled, item should not be in " + + "mMoveAnimations list"); + } + dispatchFinishedWhenDone(); + } + + public void resetAnimation(ViewHolder holder) { + AnimatorCompatHelper.clearInterpolator(holder.itemView); + endAnimation(holder); + } + + @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 {@link #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); + View view = item.itemView; + addAnimationCleanup(view); + 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; + addAnimationCleanup(view); + dispatchAddFinished(item); + 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) { + } + } +} diff --git a/library/src/main/java/com/mikepenz/itemanimators/BaseScaleAnimator.java b/library/src/main/java/com/mikepenz/itemanimators/BaseScaleAnimator.java new file mode 100644 index 0000000..163f42d --- /dev/null +++ b/library/src/main/java/com/mikepenz/itemanimators/BaseScaleAnimator.java @@ -0,0 +1,52 @@ +package com.mikepenz.itemanimators; + +import android.support.v4.view.ViewCompat; +import android.support.v7.widget.RecyclerView; +import android.view.View; + +/** + * Created by mikepenz on 08.01.16. + */ +public abstract class BaseScaleAnimator extends BaseItemAnimator { + public void changeAnimation(RecyclerView.ViewHolder oldHolder, RecyclerView.ViewHolder newHolder, int fromX, int fromY, int toX, int toY) { + final float prevTranslationX = ViewCompat.getTranslationX(oldHolder.itemView); + final float prevTranslationY = ViewCompat.getTranslationY(oldHolder.itemView); + final float prevValue = changeAnimationPrepare1(oldHolder.itemView); + resetAnimation(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); + + changeAnimationPrepare2(oldHolder.itemView, prevValue); + if (newHolder != null) { + // carry over translation values + resetAnimation(newHolder); + ViewCompat.setTranslationX(newHolder.itemView, -deltaX); + ViewCompat.setTranslationY(newHolder.itemView, -deltaY); + changeAnimationPrepare3(newHolder.itemView); + } + } + + /** + * @param view + * @return the default value for the animatd attribute + */ + abstract public float changeAnimationPrepare1(View view); + + /** + * animates the view to the previous default value + * + * @param view + * @param prevValue the previous value + */ + abstract public void changeAnimationPrepare2(View view, float prevValue); + + /** + * resets the value + * + * @param view + */ + abstract public void changeAnimationPrepare3(View view); +} diff --git a/library/src/main/java/com/mikepenz/itemanimators/DefaultAnimator.java b/library/src/main/java/com/mikepenz/itemanimators/DefaultAnimator.java new file mode 100644 index 0000000..62a32b2 --- /dev/null +++ b/library/src/main/java/com/mikepenz/itemanimators/DefaultAnimator.java @@ -0,0 +1,47 @@ +package com.mikepenz.itemanimators; + +import android.support.v4.view.ViewCompat; +import android.support.v4.view.ViewPropertyAnimatorCompat; +import android.view.View; + +/** + * Created by mikepenz on 08.01.16. + */ +public class DefaultAnimator extends BaseItemAnimator { + // ADD ANIMATION METHODS + + public void addAnimationPrepare(View view) { + ViewCompat.setAlpha(view, 0); + } + + public ViewPropertyAnimatorCompat addAnimation(View view) { + return ViewCompat.animate(view).alpha(1).setDuration(getAddDuration()).setInterpolator(getInterpolator()); + } + + public void addAnimationCleanup(View view) { + ViewCompat.setAlpha(view, 1); + } + + // REMOVE ANIMATION METHODS + + public ViewPropertyAnimatorCompat removeAnimation(View view) { + return ViewCompat.animate(view).setDuration(getRemoveDuration()).alpha(0).setInterpolator(getInterpolator()); + } + + public void removeAnimationCleanup(View view) { + ViewCompat.setAlpha(view, 1); + } + + // CHANGE ANIMATION METHODS + public ViewPropertyAnimatorCompat changeOldAnimation(View view, ChangeInfo changeInfo) { + return ViewCompat.animate(view).setDuration(getChangeDuration()).alpha(0).translationX(changeInfo.toX - changeInfo.fromX).translationY(changeInfo.toY - changeInfo.fromY).setInterpolator(getInterpolator()); + } + + public ViewPropertyAnimatorCompat changeNewAnimation(View view) { + return ViewCompat.animate(view).translationX(0).translationY(0).setDuration(getChangeDuration()).alpha(1).setInterpolator(getInterpolator()); + } + + public void changeAnimationCleanup(View view) { + ViewCompat.setAlpha(view, 1); + } +} diff --git a/library/src/main/java/com/mikepenz/itemanimators/ScaleUpAnimator.java b/library/src/main/java/com/mikepenz/itemanimators/ScaleUpAnimator.java new file mode 100644 index 0000000..d851ee4 --- /dev/null +++ b/library/src/main/java/com/mikepenz/itemanimators/ScaleUpAnimator.java @@ -0,0 +1,60 @@ +package com.mikepenz.itemanimators; + +import android.support.v4.view.ViewCompat; +import android.support.v4.view.ViewPropertyAnimatorCompat; +import android.view.View; + +/** + * Created by mikepenz on 08.01.16. + */ +public class ScaleUpAnimator extends BaseScaleAnimator { + public void addAnimationPrepare(View view) { + ViewCompat.setScaleX(view, 0); + ViewCompat.setScaleY(view, 0); + } + + public ViewPropertyAnimatorCompat addAnimation(View view) { + return ViewCompat.animate(view).scaleX(1).scaleY(1).setDuration(getAddDuration()).setInterpolator(getInterpolator()); + } + + public void addAnimationCleanup(View view) { + ViewCompat.setScaleX(view, 1); + ViewCompat.setScaleY(view, 1); + } + + + public ViewPropertyAnimatorCompat removeAnimation(View view) { + return ViewCompat.animate(view).setDuration(getRemoveDuration()).scaleX(0).scaleY(0).setInterpolator(getInterpolator()); + } + + public void removeAnimationCleanup(View view) { + ViewCompat.setScaleX(view, 1); + ViewCompat.setScaleY(view, 1); + } + + public float changeAnimationPrepare1(View view) { + return ViewCompat.getScaleX(view); + } + + public void changeAnimationPrepare2(View view, float prevValue) { + ViewCompat.setScaleX(view, prevValue); + } + + public void changeAnimationPrepare3(View view) { + ViewCompat.setScaleX(view, 0); + ViewCompat.setScaleY(view, 0); + } + + public ViewPropertyAnimatorCompat changeOldAnimation(View view, ChangeInfo changeInfo) { + return ViewCompat.animate(view).setDuration(getChangeDuration()).scaleX(0).scaleY(0).translationX(changeInfo.toX - changeInfo.fromX).translationY(changeInfo.toY - changeInfo.fromY).setInterpolator(getInterpolator()); + } + + public ViewPropertyAnimatorCompat changeNewAnimation(View view) { + return ViewCompat.animate(view).translationX(0).translationY(0).setDuration(getChangeDuration()).scaleX(1).scaleY(1).setInterpolator(getInterpolator()); + } + + public void changeAnimationCleanup(View view) { + ViewCompat.setScaleX(view, 1); + ViewCompat.setScaleY(view, 1); + } +} diff --git a/library/src/main/java/com/mikepenz/itemanimators/ScaleXAnimator.java b/library/src/main/java/com/mikepenz/itemanimators/ScaleXAnimator.java new file mode 100644 index 0000000..238448c --- /dev/null +++ b/library/src/main/java/com/mikepenz/itemanimators/ScaleXAnimator.java @@ -0,0 +1,57 @@ +package com.mikepenz.itemanimators; + +import android.support.v4.view.ViewCompat; +import android.support.v4.view.ViewPropertyAnimatorCompat; +import android.view.View; + +/** + * Created by mikepenz on 08.01.16. + */ +public class ScaleXAnimator extends BaseScaleAnimator { + public void addAnimationPrepare(View view) { + ViewCompat.setScaleX(view, 0); + } + + public ViewPropertyAnimatorCompat addAnimation(View view) { + return ViewCompat.animate(view).scaleX(1).setDuration(getAddDuration()); + } + + public void addAnimationCleanup(View view) { + ViewCompat.setScaleX(view, 1); + } + + + public ViewPropertyAnimatorCompat removeAnimation(View view) { + final ViewPropertyAnimatorCompat animation = ViewCompat.animate(view); + return animation.setDuration(getRemoveDuration()).scaleX(0); + } + + public void removeAnimationCleanup(View view) { + ViewCompat.setScaleX(view, 1); + } + + public float changeAnimationPrepare1(View view) { + return ViewCompat.getScaleX(view); + } + + public void changeAnimationPrepare2(View view, float prevValue) { + ViewCompat.setScaleX(view, prevValue); + } + + public void changeAnimationPrepare3(View view) { + ViewCompat.setScaleX(view, 0); + } + + public ViewPropertyAnimatorCompat changeOldAnimation(View view, ChangeInfo changeInfo) { + return ViewCompat.animate(view).setDuration(getChangeDuration()).scaleX(0).translationX(changeInfo.toX - changeInfo.fromX).translationY(changeInfo.toY - changeInfo.fromY); + + } + + public ViewPropertyAnimatorCompat changeNewAnimation(View view) { + return ViewCompat.animate(view).translationX(0).translationY(0).setDuration(getChangeDuration()).scaleX(1); + } + + public void changeAnimationCleanup(View view) { + ViewCompat.setScaleX(view, 1); + } +} diff --git a/library/src/main/java/com/mikepenz/itemanimators/ScaleYAnimator.java b/library/src/main/java/com/mikepenz/itemanimators/ScaleYAnimator.java new file mode 100644 index 0000000..09044ab --- /dev/null +++ b/library/src/main/java/com/mikepenz/itemanimators/ScaleYAnimator.java @@ -0,0 +1,57 @@ +package com.mikepenz.itemanimators; + +import android.support.v4.view.ViewCompat; +import android.support.v4.view.ViewPropertyAnimatorCompat; +import android.view.View; + +/** + * Created by mikepenz on 08.01.16. + */ +public class ScaleYAnimator extends BaseScaleAnimator { + public void addAnimationPrepare(View view) { + ViewCompat.setScaleY(view, 0); + } + + public ViewPropertyAnimatorCompat addAnimation(View view) { + return ViewCompat.animate(view).scaleY(1).setDuration(getAddDuration()); + } + + public void addAnimationCleanup(View view) { + ViewCompat.setScaleY(view, 1); + } + + + public ViewPropertyAnimatorCompat removeAnimation(View view) { + final ViewPropertyAnimatorCompat animation = ViewCompat.animate(view); + return animation.setDuration(getRemoveDuration()).scaleY(0); + } + + public void removeAnimationCleanup(View view) { + ViewCompat.setScaleY(view, 1); + } + + public float changeAnimationPrepare1(View view) { + return ViewCompat.getScaleY(view); + } + + public void changeAnimationPrepare2(View view, float prevValue) { + ViewCompat.setScaleY(view, prevValue); + } + + public void changeAnimationPrepare3(View view) { + ViewCompat.setScaleY(view, 0); + } + + public ViewPropertyAnimatorCompat changeOldAnimation(View view, ChangeInfo changeInfo) { + return ViewCompat.animate(view).setDuration(getChangeDuration()).scaleY(0).translationX(changeInfo.toX - changeInfo.fromX).translationY(changeInfo.toY - changeInfo.fromY); + + } + + public ViewPropertyAnimatorCompat changeNewAnimation(View view) { + return ViewCompat.animate(view).translationX(0).translationY(0).setDuration(getChangeDuration()).scaleY(1); + } + + public void changeAnimationCleanup(View view) { + ViewCompat.setScaleY(view, 1); + } +} diff --git a/library/src/main/java/com/mikepenz/itemanimators/SlideDownAlphaAnimator.java b/library/src/main/java/com/mikepenz/itemanimators/SlideDownAlphaAnimator.java new file mode 100644 index 0000000..4492042 --- /dev/null +++ b/library/src/main/java/com/mikepenz/itemanimators/SlideDownAlphaAnimator.java @@ -0,0 +1,49 @@ +package com.mikepenz.itemanimators; + +import android.support.v4.view.ViewCompat; +import android.support.v4.view.ViewPropertyAnimatorCompat; +import android.view.View; + +/** + * Created by mikepenz on 08.01.16. + */ +public class SlideDownAlphaAnimator extends DefaultAnimator { + @Override + public void addAnimationPrepare(View view) { + ViewCompat.setTranslationY(view, -view.getHeight()); + ViewCompat.setAlpha(view, 0); + } + + @Override + public ViewPropertyAnimatorCompat addAnimation(View view) { + return ViewCompat.animate(view).translationY(0).alpha(1).setDuration(getMoveDuration()); + } + + @Override + public void addAnimationCleanup(View view) { + ViewCompat.setTranslationY(view, 0); + ViewCompat.setAlpha(view, 1); + } + + @Override + public long getAddDelay(long remove, long move, long change) { + return 0; + } + + @Override + public long getRemoveDelay(long remove, long move, long change) { + return remove / 2; + } + + @Override + public ViewPropertyAnimatorCompat removeAnimation(View view) { + final ViewPropertyAnimatorCompat animation = ViewCompat.animate(view); + return animation.setDuration(getMoveDuration()).alpha(0).translationY(-view.getHeight()); + } + + @Override + public void removeAnimationCleanup(View view) { + ViewCompat.setTranslationY(view, 0); + ViewCompat.setAlpha(view, 1); + } +} diff --git a/library/src/main/java/com/mikepenz/itemanimators/SlideLeftAlphaAnimator.java b/library/src/main/java/com/mikepenz/itemanimators/SlideLeftAlphaAnimator.java new file mode 100644 index 0000000..43f0e74 --- /dev/null +++ b/library/src/main/java/com/mikepenz/itemanimators/SlideLeftAlphaAnimator.java @@ -0,0 +1,49 @@ +package com.mikepenz.itemanimators; + +import android.support.v4.view.ViewCompat; +import android.support.v4.view.ViewPropertyAnimatorCompat; +import android.view.View; + +/** + * Created by mikepenz on 08.01.16. + */ +public class SlideLeftAlphaAnimator extends DefaultAnimator { + @Override + public void addAnimationPrepare(View view) { + ViewCompat.setTranslationX(view, view.getWidth()); + ViewCompat.setAlpha(view, 0); + } + + @Override + public ViewPropertyAnimatorCompat addAnimation(View view) { + return ViewCompat.animate(view).translationX(0).alpha(1).setDuration(getMoveDuration()); + } + + @Override + public void addAnimationCleanup(View view) { + ViewCompat.setTranslationX(view, 0); + ViewCompat.setAlpha(view, 1); + } + + @Override + public long getAddDelay(long remove, long move, long change) { + return 0; + } + + @Override + public long getRemoveDelay(long remove, long move, long change) { + return 0; + } + + @Override + public ViewPropertyAnimatorCompat removeAnimation(View view) { + final ViewPropertyAnimatorCompat animation = ViewCompat.animate(view); + return animation.setDuration(getMoveDuration()).alpha(0).translationX(view.getWidth()); + } + + @Override + public void removeAnimationCleanup(View view) { + ViewCompat.setTranslationX(view, 0); + ViewCompat.setAlpha(view, 1); + } +} diff --git a/library/src/main/java/com/mikepenz/itemanimators/SlideRightAlphaAnimator.java b/library/src/main/java/com/mikepenz/itemanimators/SlideRightAlphaAnimator.java new file mode 100644 index 0000000..fa132e1 --- /dev/null +++ b/library/src/main/java/com/mikepenz/itemanimators/SlideRightAlphaAnimator.java @@ -0,0 +1,49 @@ +package com.mikepenz.itemanimators; + +import android.support.v4.view.ViewCompat; +import android.support.v4.view.ViewPropertyAnimatorCompat; +import android.view.View; + +/** + * Created by mikepenz on 08.01.16. + */ +public class SlideRightAlphaAnimator extends DefaultAnimator { + @Override + public void addAnimationPrepare(View view) { + ViewCompat.setTranslationX(view, -view.getWidth()); + ViewCompat.setAlpha(view, 0); + } + + @Override + public ViewPropertyAnimatorCompat addAnimation(View view) { + return ViewCompat.animate(view).translationX(0).alpha(1).setDuration(getMoveDuration()); + } + + @Override + public void addAnimationCleanup(View view) { + ViewCompat.setTranslationX(view, 0); + ViewCompat.setAlpha(view, 1); + } + + @Override + public long getAddDelay(long remove, long move, long change) { + return 0; + } + + @Override + public long getRemoveDelay(long remove, long move, long change) { + return 0; + } + + @Override + public ViewPropertyAnimatorCompat removeAnimation(View view) { + final ViewPropertyAnimatorCompat animation = ViewCompat.animate(view); + return animation.setDuration(getMoveDuration()).alpha(0).translationX(-view.getWidth()); + } + + @Override + public void removeAnimationCleanup(View view) { + ViewCompat.setTranslationX(view, 0); + ViewCompat.setAlpha(view, 1); + } +} diff --git a/library/src/main/java/com/mikepenz/itemanimators/SlideUpAlphaAnimator.java b/library/src/main/java/com/mikepenz/itemanimators/SlideUpAlphaAnimator.java new file mode 100644 index 0000000..fc59859 --- /dev/null +++ b/library/src/main/java/com/mikepenz/itemanimators/SlideUpAlphaAnimator.java @@ -0,0 +1,49 @@ +package com.mikepenz.itemanimators; + +import android.support.v4.view.ViewCompat; +import android.support.v4.view.ViewPropertyAnimatorCompat; +import android.view.View; + +/** + * Created by mikepenz on 08.01.16. + */ +public class SlideUpAlphaAnimator extends DefaultAnimator { + @Override + public void addAnimationPrepare(View view) { + ViewCompat.setTranslationY(view, view.getHeight()); + ViewCompat.setAlpha(view, 0); + } + + @Override + public ViewPropertyAnimatorCompat addAnimation(View view) { + return ViewCompat.animate(view).translationY(0).alpha(1).setDuration(getMoveDuration()); + } + + @Override + public void addAnimationCleanup(View view) { + ViewCompat.setTranslationY(view, 0); + ViewCompat.setAlpha(view, 1); + } + + @Override + public long getAddDelay(long remove, long move, long change) { + return 0; + } + + @Override + public long getRemoveDelay(long remove, long move, long change) { + return 0; + } + + @Override + public ViewPropertyAnimatorCompat removeAnimation(View view) { + final ViewPropertyAnimatorCompat animation = ViewCompat.animate(view); + return animation.setDuration(getMoveDuration()).alpha(0).translationY(view.getHeight()); + } + + @Override + public void removeAnimationCleanup(View view) { + ViewCompat.setTranslationY(view, 0); + ViewCompat.setAlpha(view, 1); + } +} diff --git a/library/src/main/res/values/library_itemanimators_strings.xml b/library/src/main/res/values/library_itemanimators_strings.xml new file mode 100755 index 0000000..72fa21c --- /dev/null +++ b/library/src/main/res/values/library_itemanimators_strings.xml @@ -0,0 +1,21 @@ + + + + year;owner + Mike Penz + http://mikepenz.com/ + itemanimators + + ItemAnimators library comes with a huge collections of pre-created Animators for your RecyclerView. + ]]> + + 0.0.1-SNAPSHOT + https://github.com/mikepenz/itemanimators + apache_2_0 + true + https://github.com/mikepenz/itemanimators + + Mike Penz + 2016 + diff --git a/settings.gradle b/settings.gradle new file mode 100644 index 0000000..ef1bbc7 --- /dev/null +++ b/settings.gradle @@ -0,0 +1,2 @@ +include ':app' +include ':library' \ No newline at end of file From 80dc66c2e3e2e6492cc6003b3ee95979d41e4fa1 Mon Sep 17 00:00:00 2001 From: Mike Penz Date: Sat, 9 Jan 2016 18:57:13 +0100 Subject: [PATCH 2/3] * fix title --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 3b73b99..f92de4f 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -#itemanimators [![Maven Central](https://maven-badges.herokuapp.com/maven-central/com.mikepenz/itemanimators/badge.svg?style=flat)](https://maven-badges.herokuapp.com/maven-central/com.mikepenz/itemanimators) [![Join the chat at https://gitter.im/mikepenz/itemanimators](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/mikepenz/itemanimators?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) +#ItemAnimators [![Maven Central](https://maven-badges.herokuapp.com/maven-central/com.mikepenz/itemanimators/badge.svg?style=flat)](https://maven-badges.herokuapp.com/maven-central/com.mikepenz/itemanimators) [![Join the chat at https://gitter.im/mikepenz/itemanimators](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/mikepenz/itemanimators?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) The **ItemAnimators** library comes with a huge collections of pre-created Animators for your RecyclerView. It was created so developers can easly animate their RecyclerView. It also takes care about correctly handling all view states so you don't have to. From 89bbdef82f1ea0d6165590c2b538161cf7f74a8d Mon Sep 17 00:00:00 2001 From: Mike Penz Date: Sat, 9 Jan 2016 18:58:07 +0100 Subject: [PATCH 3/3] * [pre-release] v0.1.0-SNAPSHOT --- README.md | 2 +- app/build.gradle | 4 ++-- gradle.properties | 4 ++-- library/build.gradle | 4 ++-- library/src/main/res/values/library_itemanimators_strings.xml | 2 +- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index f92de4f..82236f5 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ It was created so developers can easly animate their RecyclerView. It also takes #Include in your project ##Using Maven ```javascript -compile('com.mikepenz:itemanimators:0.0.1-SNAPSHOT@aar') { +compile('com.mikepenz:itemanimators:0.1.0-SNAPSHOT@aar') { transitive = true } diff --git a/app/build.gradle b/app/build.gradle index d662f29..26afe04 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -12,8 +12,8 @@ android { defaultConfig { minSdkVersion 11 targetSdkVersion 23 - versionCode 1 - versionName '0.0.1-SNAPSHOT' + versionCode 10 + versionName '0.1.0-SNAPSHOT' applicationVariants.all { variant -> variant.outputs.each { output -> diff --git a/gradle.properties b/gradle.properties index 18cd624..0c11840 100644 --- a/gradle.properties +++ b/gradle.properties @@ -19,8 +19,8 @@ org.gradle.daemon=true org.gradle.parallel=true # Maven stuff -VERSION_NAME=0.0.1-SNAPSHOT -VERSION_CODE=1 +VERSION_NAME=0.1.0-SNAPSHOT +VERSION_CODE=10 GROUP=com.mikepenz POM_DESCRIPTION=ItemAnimators Library diff --git a/library/build.gradle b/library/build.gradle index 2a7e9ca..50db719 100644 --- a/library/build.gradle +++ b/library/build.gradle @@ -8,8 +8,8 @@ android { defaultConfig { minSdkVersion 10 targetSdkVersion 23 - versionCode 1 - versionName '0.0.1-SNAPSHOT' + versionCode 10 + versionName '0.1.0-SNAPSHOT' } buildTypes { release { diff --git a/library/src/main/res/values/library_itemanimators_strings.xml b/library/src/main/res/values/library_itemanimators_strings.xml index 72fa21c..9eb289a 100755 --- a/library/src/main/res/values/library_itemanimators_strings.xml +++ b/library/src/main/res/values/library_itemanimators_strings.xml @@ -10,7 +10,7 @@ The ItemAnimators library comes with a huge collections of pre-created Animators for your RecyclerView. ]]> - 0.0.1-SNAPSHOT + 0.1.0-SNAPSHOT https://github.com/mikepenz/itemanimators apache_2_0 true