diff --git a/app/src/main/java/com/hippo/animation/SimpleAnimatorListener.java b/app/src/main/java/com/hippo/animation/SimpleAnimatorListener.java index 827fbb8b3..ef892e630 100644 --- a/app/src/main/java/com/hippo/animation/SimpleAnimatorListener.java +++ b/app/src/main/java/com/hippo/animation/SimpleAnimatorListener.java @@ -17,18 +17,26 @@ package com.hippo.animation; import android.animation.Animator; -public class SimpleAnimatorListener implements Animator.AnimatorListener { +public abstract class SimpleAnimatorListener implements Animator.AnimatorListener { + + private boolean mCanceled; @Override public void onAnimationStart(Animator animation) { + mCanceled = false; } @Override public void onAnimationEnd(Animator animation) { + onAnimationEnd(animation, mCanceled); + } + + public void onAnimationEnd(Animator animation, boolean canceled) { } @Override public void onAnimationCancel(Animator animation) { + mCanceled = true; } @Override diff --git a/app/src/main/java/com/hippo/effect/ViewTransition.java b/app/src/main/java/com/hippo/effect/ViewTransition.java index d760f39ea..b88857f49 100644 --- a/app/src/main/java/com/hippo/effect/ViewTransition.java +++ b/app/src/main/java/com/hippo/effect/ViewTransition.java @@ -18,7 +18,7 @@ package com.hippo.effect; import android.animation.Animator; import android.animation.ObjectAnimator; import android.os.Build; -import android.support.annotation.NonNull; +import android.view.RenderNodeAnimator; import android.view.View; import com.hippo.animation.SimpleAnimatorListener; @@ -28,99 +28,166 @@ public class ViewTransition { private static long ANIMATE_TIME = 300L; - private View mView1; - private View mView2; - private boolean mSwitch = false; + private final View[] mViews; - public ViewTransition(@NonNull View view1, @NonNull View view2) { - mView1 = view1; - mView2 = view2; + private int mShownView = -1; - ViewUtils.setVisibility(view1, View.VISIBLE); - ViewUtils.setVisibility(view2, View.GONE); - } + private Animator mAnimator1; + private Animator mAnimator2; - public void toggle() { - if (mSwitch) { - showFirstView(); - } else { - showSecondView(); + public ViewTransition(View... views) { + if (views.length < 2) { + throw new IllegalStateException("You must pass view to ViewTransition"); } + for (View v : views) { + if (v == null) { + throw new IllegalStateException("Any View pass to ViewTransition must not be null"); + } + } + + mViews = views; + showView(0, false); } - public void showFirstView() { - showFirstView(true); + public void showView(int shownView) { + showView(shownView, true); } - public void showFirstView(boolean animation) { - if (mSwitch) { - mSwitch = false; + public void showView(int shownView, boolean animation) { + View[] views = mViews; + int length = views.length; + if (shownView >= length || shownView < 0) { + throw new IndexOutOfBoundsException("Only " + length + " view(s) in " + + "the ViewTransition, but attempt to show " + shownView); + } + + if (mShownView != shownView) { + int oldShownView = mShownView; + mShownView = shownView; + + // Cancel animation + if (mAnimator1 != null) { + mAnimator1.cancel(); + } + if (mAnimator2 != null) { + mAnimator2.cancel(); + } if (animation) { - ObjectAnimator oa1 = ObjectAnimator.ofFloat(mView1, "alpha", 0f, 1f); - oa1.setDuration(ANIMATE_TIME); - oa1.addListener(new SimpleAnimatorListener() { - @Override - public void onAnimationStart(Animator animation) { - ViewUtils.setVisibility(mView1, View.VISIBLE); + for (int i = 0; i < length; i++) { + if (i != oldShownView && i != shownView) { + View v = views[i]; + v.setAlpha(0f); + ViewUtils.setVisibility(v, View.GONE); } - }); - ObjectAnimator oa2 = ObjectAnimator.ofFloat(mView2, "alpha", 1f, 0f); - oa2.setDuration(ANIMATE_TIME); - oa2.addListener(new SimpleAnimatorListener() { - @Override - public void onAnimationEnd(Animator animation) { - ViewUtils.setVisibility(mView2, View.GONE); - } - }); - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) { - oa1.setAutoCancel(true); - oa2.setAutoCancel(true); } - oa1.start(); - oa2.start(); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + startAnimationsL(views[oldShownView], views[shownView]); + } else { + startAnimations(views[oldShownView], views[shownView]); + } } else { - ViewUtils.setVisibility(mView1, View.VISIBLE); - ViewUtils.setVisibility(mView2, View.GONE); + for (int i = 0; i < length; i++) { + View v = views[i]; + if (i == shownView) { + v.setAlpha(1f); + ViewUtils.setVisibility(v, View.VISIBLE); + } else { + v.setAlpha(0f); + ViewUtils.setVisibility(v, View.GONE); + } + } } } } - public void showSecondView() { - showSecondView(true); + private void startAnimationsL(final View hiddenView, View shownView) { + RenderNodeAnimator rna1 = new RenderNodeAnimator(RenderNodeAnimator.ALPHA, 0f); + rna1.setTarget(hiddenView); + rna1.setDuration(ANIMATE_TIME); + rna1.addListener(new SimpleAnimatorListener() { + @Override + public void onAnimationCancel(Animator animation) { + super.onAnimationCancel(animation); + mAnimator1 = null; + } + + @Override + public void onAnimationEnd(Animator animation, boolean canceled) { + super.onAnimationEnd(animation, canceled); + if (!canceled) { + ViewUtils.setVisibility(hiddenView, View.GONE); + mAnimator1 = null; + } + } + }); + rna1.start(); + mAnimator1 = rna1; + + ViewUtils.setVisibility(shownView, View.VISIBLE); + RenderNodeAnimator rna2 = new RenderNodeAnimator(RenderNodeAnimator.ALPHA, 1f); + rna2.setTarget(shownView); + rna2.setDuration(ANIMATE_TIME); + rna2.addListener(new SimpleAnimatorListener() { + @Override + public void onAnimationCancel(Animator animation) { + super.onAnimationCancel(animation); + mAnimator2 = null; + } + + @Override + public void onAnimationEnd(Animator animation, boolean canceled) { + super.onAnimationEnd(animation, canceled); + if (!canceled) { + mAnimator2 = null; + } + } + }); + rna2.start(); + mAnimator2 = rna2; } - public void showSecondView(boolean animation) { - if (!mSwitch) { - mSwitch = true; - - if (animation) { - ObjectAnimator oa1 = ObjectAnimator.ofFloat(mView1, "alpha", 1f, 0f); - oa1.setDuration(ANIMATE_TIME); - oa1.addListener(new SimpleAnimatorListener() { - @Override - public void onAnimationEnd(Animator animation) { - ViewUtils.setVisibility(mView1, View.GONE); - } - }); - ObjectAnimator oa2 = ObjectAnimator.ofFloat(mView2, "alpha", 0f, 1f); - oa2.setDuration(ANIMATE_TIME); - oa2.addListener(new SimpleAnimatorListener() { - @Override - public void onAnimationStart(Animator animation) { - ViewUtils.setVisibility(mView2, View.VISIBLE); - } - }); - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) { - oa1.setAutoCancel(true); - oa2.setAutoCancel(true); - } - oa1.start(); - oa2.start(); - } else { - ViewUtils.setVisibility(mView1, View.GONE); - ViewUtils.setVisibility(mView2, View.VISIBLE); + private void startAnimations(final View hiddenView, final View shownView) { + ObjectAnimator oa1 = ObjectAnimator.ofFloat(hiddenView, "alpha", 0f); + oa1.setDuration(ANIMATE_TIME); + oa1.addListener(new SimpleAnimatorListener() { + @Override + public void onAnimationCancel(Animator animation) { + super.onAnimationCancel(animation); + mAnimator1 = null; } - } + + @Override + public void onAnimationEnd(Animator animation, boolean canceled) { + super.onAnimationEnd(animation, canceled); + if (!canceled) { + ViewUtils.setVisibility(hiddenView, View.GONE); + mAnimator1 = null; + } + } + }); + oa1.start(); + mAnimator1 = oa1; + + ViewUtils.setVisibility(shownView, View.VISIBLE); + ObjectAnimator oa2 = ObjectAnimator.ofFloat(shownView, "alpha", 1f); + oa2.setDuration(ANIMATE_TIME); + oa2.addListener(new SimpleAnimatorListener() { + @Override + public void onAnimationCancel(Animator animation) { + super.onAnimationCancel(animation); + mAnimator2 = null; + } + + @Override + public void onAnimationEnd(Animator animation, boolean canceled) { + super.onAnimationEnd(animation, canceled); + if (!canceled) { + mAnimator2 = null; + } + } + }); + oa2.start(); + mAnimator2 = oa2; } } diff --git a/app/src/main/java/com/hippo/ehviewer/ui/scene/GalleryListScene.java b/app/src/main/java/com/hippo/ehviewer/ui/scene/GalleryListScene.java index 9b28cd4f2..ae4698e9b 100644 --- a/app/src/main/java/com/hippo/ehviewer/ui/scene/GalleryListScene.java +++ b/app/src/main/java/com/hippo/ehviewer/ui/scene/GalleryListScene.java @@ -180,11 +180,11 @@ public class GalleryListScene extends Scene implements SearchBar.Helper, switch (mState) { case STATE_NORMAL: case STATE_SIMPLE_SEARCH: - mViewTransition.showFirstView(false); + mViewTransition.showView(0, false); break; case STATE_SEARCH: case STATE_SEARCH_SHOW_LIST: - mViewTransition.showSecondView(false); + mViewTransition.showView(1, false); break; } @@ -259,7 +259,7 @@ public class GalleryListScene extends Scene implements SearchBar.Helper, break; case STATE_SEARCH: mState = STATE_NORMAL; - mViewTransition.showFirstView(); + mViewTransition.showView(0); mSearchBar.setState(SearchBar.STATE_NORMAL); returnSearchBarPosition(); setFabState(FAB_STATE_NORMAL); @@ -323,7 +323,7 @@ public class GalleryListScene extends Scene implements SearchBar.Helper, public void onClickAdvanceSearch() { if (mState == STATE_NORMAL) { mState = STATE_SEARCH; - mViewTransition.showSecondView(); + mViewTransition.showView(1); mSearchLayout.scrollSearchContainerToTop(); mSearchBar.setState(SearchBar.STATE_SEARCH); returnSearchBarPosition(); @@ -347,7 +347,7 @@ public class GalleryListScene extends Scene implements SearchBar.Helper, mSearchDatabase.addQuery(query); mState = STATE_NORMAL; - mViewTransition.showFirstView(); + mViewTransition.showView(0); mSearchBar.setState(SearchBar.STATE_NORMAL); returnSearchBarPosition(); setFabState(FAB_STATE_NORMAL); diff --git a/app/src/main/java/com/hippo/ehviewer/widget/SearchBar.java b/app/src/main/java/com/hippo/ehviewer/widget/SearchBar.java index c6ca9fd20..154518f12 100644 --- a/app/src/main/java/com/hippo/ehviewer/widget/SearchBar.java +++ b/app/src/main/java/com/hippo/ehviewer/widget/SearchBar.java @@ -249,7 +249,7 @@ public class SearchBar extends CardView implements View.OnClickListener, switch (oldState) { default: case STATE_NORMAL: - mViewTransition.showSecondView(animation); + mViewTransition.showView(1); mEditText.requestFocus(); mDrawerArrowDrawable.setArrow(animation ? ANIMATE_TIME : 0); mAddDeleteDrawable.setDelete(animation ? ANIMATE_TIME : 0); @@ -259,7 +259,7 @@ public class SearchBar extends CardView implements View.OnClickListener, break; case STATE_SEARCH: if (state == STATE_NORMAL) { - mViewTransition.showFirstView(animation); + mViewTransition.showView(0); mDrawerArrowDrawable.setMenu(animation ? ANIMATE_TIME : 0); mAddDeleteDrawable.setAdd(animation ? ANIMATE_TIME : 0); } else if (state == STATE_SEARCH_LIST) { @@ -269,7 +269,7 @@ public class SearchBar extends CardView implements View.OnClickListener, case STATE_SEARCH_LIST: hideImeAndSuggestionsList(animation); if (state == STATE_NORMAL) { - mViewTransition.showFirstView(animation); + mViewTransition.showView(0); mDrawerArrowDrawable.setMenu(animation ? ANIMATE_TIME : 0); mAddDeleteDrawable.setAdd(animation ? ANIMATE_TIME : 0); }