From 8757d41b120632243f84f2ebacfa9aedb77a77f0 Mon Sep 17 00:00:00 2001 From: Heinrich Reimer Date: Tue, 21 Mar 2017 04:52:39 +0100 Subject: [PATCH] Add navigation interface to make slide navigation consistent between IntroActivity and SlideFragment (fix #155, fix #156, fix #166), fix #162 --- .../materialintro/app/IntroActivity.java | 102 +++++++++++++----- .../materialintro/app/IntroNavigation.java | 47 ++++++++ .../materialintro/app/SlideFragment.java | 27 ++++- .../materialintro/slide/SlideAdapter.java | 3 +- 4 files changed, 147 insertions(+), 32 deletions(-) create mode 100644 library/src/main/java/com/heinrichreimersoftware/materialintro/app/IntroNavigation.java diff --git a/library/src/main/java/com/heinrichreimersoftware/materialintro/app/IntroActivity.java b/library/src/main/java/com/heinrichreimersoftware/materialintro/app/IntroActivity.java index e349279..7d7c7c3 100644 --- a/library/src/main/java/com/heinrichreimersoftware/materialintro/app/IntroActivity.java +++ b/library/src/main/java/com/heinrichreimersoftware/materialintro/app/IntroActivity.java @@ -68,7 +68,7 @@ import java.util.List; @SuppressLint("Registered") -public class IntroActivity extends AppCompatActivity { +public class IntroActivity extends AppCompatActivity implements IntroNavigation { private static final String KEY_CURRENT_ITEM = "com.heinrichreimersoftware.materialintro.app.IntroActivity.KEY_CURRENT_ITEM"; private static final String KEY_FULLSCREEN = @@ -366,42 +366,81 @@ private long calculateScrollDuration(int distance) { return Math.round(pageScrollDuration * (distance + Math.sqrt(distance)) / 2); } - public void nextSlide() { - int currentItem = pager.getCurrentItem(); - if (currentItem > adapter.getCount() - 1) finishIfNeeded(); + @Override + public boolean goToSlide(int position) { + int lastPosition = pager.getCurrentItem(); - if (canGoForward(currentItem, true)) { - smoothScrollPagerTo(++currentItem); + if (lastPosition >= adapter.getCount()) { + finishIfNeeded(); + } + + int newPosition = lastPosition; + + position = Math.max(0, Math.min(position, getCount())); + + if (position > lastPosition) { + // Go forward + while (newPosition < position && canGoForward(newPosition, true)) { + newPosition++; + } + } else if (position < lastPosition) { + // Go backward + while (newPosition > position && canGoBackward(newPosition, true)) { + newPosition--; + } } else { - AnimUtils.applyShakeAnimation(this, buttonNext); + // Noting to do here + return true; } + + boolean blocked = false; + if (newPosition != position) { + // Could not go the complete way to the given position. + blocked = true; + + if (position > lastPosition) { + AnimUtils.applyShakeAnimation(this, buttonNext); + } else if (position < lastPosition) { + AnimUtils.applyShakeAnimation(this, buttonBack); + } + } + + // Scroll to new position + smoothScrollPagerTo(newPosition); + + return !blocked; + } + + @Override + public boolean nextSlide() { + int currentItem = pager.getCurrentItem(); + return goToSlide(currentItem + 1); } private int nextSlideAuto() { - int endPosition = pager.getCurrentItem(); + int lastPosition = pager.getCurrentItem(); int count = getCount(); if (count == 1) { return 0; } else if (pager.getCurrentItem() >= count - 1) { - while (endPosition >= 0 && canGoBackward(endPosition, true)) { - endPosition--; + while (lastPosition >= 0 && canGoBackward(lastPosition, true)) { + lastPosition--; } if (autoplayCounter > 0) autoplayCounter--; - } - else if (canGoForward(endPosition, true)) { - endPosition++; + } else if (canGoForward(lastPosition, true)) { + lastPosition++; } - int distance = Math.abs(endPosition - pager.getCurrentItem()); + int distance = Math.abs(lastPosition - pager.getCurrentItem()); - if (endPosition == pager.getCurrentItem()) + if (lastPosition == pager.getCurrentItem()) return 0; - smoothScrollPagerTo(endPosition); + smoothScrollPagerTo(lastPosition); if (autoplayCounter == 0) return 0; @@ -409,17 +448,20 @@ else if (canGoForward(endPosition, true)) { } - public void previousSlide() { + @Override + public boolean previousSlide() { int currentItem = pager.getCurrentItem(); - if (currentItem <= 0) return; + return goToSlide(currentItem - 1); + } - if (canGoBackward(currentItem, true)) { - smoothScrollPagerTo(--currentItem); - } - else { - AnimUtils.applyShakeAnimation(this, buttonBack); + @Override + public boolean goToLastSlide() { + return goToSlide(getCount() - 1); + } - } + @Override + public boolean goToFirstSlide() { + return goToSlide(0); } private void performButtonBackPress() { @@ -436,8 +478,12 @@ private void performButtonBackPress() { } private boolean canGoForward(int position, boolean notifyListeners) { - if (position >= getCount()) + if (position >= getCount()) { return false; + } + if (position <= 0) { + return true; + } if (buttonNextFunction == BUTTON_NEXT_FUNCTION_NEXT && position >= getCount() - 1) //Block finishing when button "next" function is not "finish". @@ -454,8 +500,12 @@ private boolean canGoForward(int position, boolean notifyListeners) { } private boolean canGoBackward(int position, boolean notifyListeners) { - if (position <= 0) + if (position <= 0) { return false; + } + if (position >= getCount()) { + return true; + } boolean canGoBackward = (navigationPolicy == null || navigationPolicy.canGoBackward(position)) && getSlide(position).canGoBackward(); diff --git a/library/src/main/java/com/heinrichreimersoftware/materialintro/app/IntroNavigation.java b/library/src/main/java/com/heinrichreimersoftware/materialintro/app/IntroNavigation.java new file mode 100644 index 0000000..66e1390 --- /dev/null +++ b/library/src/main/java/com/heinrichreimersoftware/materialintro/app/IntroNavigation.java @@ -0,0 +1,47 @@ +package com.heinrichreimersoftware.materialintro.app; + +interface IntroNavigation { + /** + * Tries to go to the given position and will stop when {@code canGoForward()} or + * {@code canGoBackward()} returns {@code false}. + * + * @param position The position the pager should go to. + * @return {@code true} if the pager was able to go the complete way to the given position, + * {@code false} otherwise. + */ + boolean goToSlide(int position); + + /** + * Tries to go to the next slide if {@code canGoForward()} returns {@code true}. + * + * @return {@code true} if the pager was able to go to the next slide, {@code false} otherwise. + */ + boolean nextSlide(); + + + /** + * Tries to go to the previous slide if {@code canGoForward()} returns {@code true}. + * + * @return {@code true} if the pager was able to go to the previous slide, {@code false} + * otherwise. + */ + boolean previousSlide(); + + /** + * Tries to go to the last slide and will stop when {@code canGoForward()} returns + * {@code false}. + * + * @return {@code true} if the pager was able to go the complete way to the last slide, + * {@code false} otherwise. + */ + boolean goToLastSlide(); + + /** + * Tries to go to the first slide and will stop when {@code canGoBackward()} returns + * {@code false}. + * + * @return {@code true} if the pager was able to go the complete way to the first slide, + * {@code false} otherwise. + */ + boolean goToFirstSlide(); +} diff --git a/library/src/main/java/com/heinrichreimersoftware/materialintro/app/SlideFragment.java b/library/src/main/java/com/heinrichreimersoftware/materialintro/app/SlideFragment.java index 6055e57..b7a14ae 100644 --- a/library/src/main/java/com/heinrichreimersoftware/materialintro/app/SlideFragment.java +++ b/library/src/main/java/com/heinrichreimersoftware/materialintro/app/SlideFragment.java @@ -3,7 +3,7 @@ import android.support.v4.app.Fragment; import android.view.View; -public class SlideFragment extends Fragment { +public class SlideFragment extends Fragment implements IntroNavigation { public boolean canGoForward() { return true; @@ -33,12 +33,29 @@ public void removeOnNavigationBlockedListener(OnNavigationBlockedListener listen getIntroActivity().removeOnNavigationBlockedListener(listener); } - protected void nextSlide() { - getIntroActivity().nextSlide(); + @Override + public boolean goToSlide(int position) { + return getIntroActivity().goToSlide(position); } - protected void previousSlide() { - getIntroActivity().previousSlide(); + @Override + public boolean nextSlide() { + return getIntroActivity().nextSlide(); + } + + @Override + public boolean previousSlide() { + return getIntroActivity().previousSlide(); + } + + @Override + public boolean goToLastSlide() { + return getIntroActivity().goToLastSlide(); + } + + @Override + public boolean goToFirstSlide() { + return getIntroActivity().goToFirstSlide(); } /** diff --git a/library/src/main/java/com/heinrichreimersoftware/materialintro/slide/SlideAdapter.java b/library/src/main/java/com/heinrichreimersoftware/materialintro/slide/SlideAdapter.java index a9dace8..b9e23b7 100644 --- a/library/src/main/java/com/heinrichreimersoftware/materialintro/slide/SlideAdapter.java +++ b/library/src/main/java/com/heinrichreimersoftware/materialintro/slide/SlideAdapter.java @@ -125,8 +125,9 @@ public Object instantiateItem(ViewGroup container, int position) { //Load old fragment from fragment manager ((RestorableSlide) slide).setFragment(instantiatedFragment); data.set(position, slide); - if (instantiatedFragment instanceof SlideFragment) + if (instantiatedFragment instanceof SlideFragment && instantiatedFragment.isAdded()) { ((SlideFragment) instantiatedFragment).updateNavigation(); + } } return instantiatedFragment; }