From 52da748fda5df431c9086b5bd530e9e0debf5f8d Mon Sep 17 00:00:00 2001 From: Sira Lam Date: Thu, 21 Dec 2017 15:53:46 +0800 Subject: [PATCH] Solved a bug where getSelectinIndicatorPosition() is returning wrong value --- README.md | 22 +++- app/build.gradle | 2 +- .../loopingviewpagerdemo/MainActivity.java | 2 +- app/src/main/res/layout/activity_main.xml | 2 +- loopingviewpager/build.gradle | 6 +- .../loopingviewpager/LoopingPagerAdapter.java | 6 +- .../loopingviewpager/LoopingViewPager.java | 102 ++++++++++++------ 7 files changed, 99 insertions(+), 43 deletions(-) diff --git a/README.md b/README.md index d51be1f..a1794bd 100644 --- a/README.md +++ b/README.md @@ -174,7 +174,6 @@ And here is an example using [PageIndicatorView](https://github.com/romandanylyk viewPager.setIndicatorPageChangeListener(new LoopingViewPager.IndicatorPageChangeListener() { @Override public void onIndicatorProgress(int selectingPosition, float progress) { - indicatorView.setProgress(selectingPosition, progress); } @Override @@ -192,7 +191,26 @@ indicatorView.setCount(viewPager.getIndicatorCount()); By implementing this way, you can basically use any indicators you like, as long as that indicator allows you to configure programmatically (1) The number of indicators; (2) Which indicator is selected. And even, if it supports, (3) The progress of indicator transition effect. -**P.S.** However, due to [this bug of PageIndicatorView](https://github.com/romandanylyk/PageIndicatorView/issues/51), the transition effect on indicators cannot be shown until the author release [his fix in development branch](https://github.com/romandanylyk/PageIndicatorView/commit/3df8093276afa1e4d1f477444df3a20ce801a235). +### Wait, if you want interactive indicator transition effect, please read this section + +However, due to [this bug of PageIndicatorView](https://github.com/romandanylyk/PageIndicatorView/issues), the interactive transition effect on indicators cannot work properly. + +LoopingViewPager will trigger `onIndicatorProgress()` when scroll state of `LoopingViewPager` is `SCROLL_STATE_DRAGGING`. +It will not trigger `onIndicatorProgress()` if scroll state is `SCROLL_STATE_SETTLING`. +In fact, when user releases his finger during swiping (where scroll state changes from `SCROLL_STATE_DRAGGING` to `SCROLL_STATE_SETTLING`), `onPageSelected()` will be called and therefore `onIndicatorPageChange()`. +LoopingViewPager expects the indicator will be able to **finish the animation by itself** after `indicatorView.setSelection()` (Or corresponding method of other libraries). + +(In fact, I tried to trigger `onIndicatorProgress()` even when scroll state is `SCROLL_STATE_SETTLING`. At first it seems to work good. +However, I cannot find a way to avoid problems that occur when user swipe fastly, i.e. from `SCROLL_STATE_SETTLING` directly to `SCROLL_STATE_DRAGGING` again **before the next page is selected**. So I decided to let indicator handles this.) + +For now, if you use [PageIndicatorView](https://github.com/romandanylyk/PageIndicatorView/), do not call anything in `onIndicatorProgress()`. +If you really want the interactive transition effect during `SCROLL_STATE_DRAGGING`, I would suggest you use another library or implement your own one. + +## Release notes + +v1.0.1 +- Fixed a bug where getSelectingIndicatorPosition() is returning incorrect value. +- Updated README.md according to PageIndicatorView v1.0.0 update. ## License diff --git a/app/build.gradle b/app/build.gradle index bfdb2f5..618f717 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -22,7 +22,7 @@ dependencies { implementation fileTree(include: ['*.jar'], dir: 'libs') implementation 'com.android.support:appcompat-v7:26.1.0' implementation 'com.android.support.constraint:constraint-layout:1.0.2' - implementation 'com.romandanylyk:pageindicatorview:0.2.0' + implementation 'com.romandanylyk:pageindicatorview:1.0.0' testImplementation 'junit:junit:4.12' androidTestImplementation 'com.android.support.test:runner:1.0.1' androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.1' diff --git a/app/src/main/java/com/asksira/loopingviewpagerdemo/MainActivity.java b/app/src/main/java/com/asksira/loopingviewpagerdemo/MainActivity.java index 6bd99f3..ad81c96 100644 --- a/app/src/main/java/com/asksira/loopingviewpagerdemo/MainActivity.java +++ b/app/src/main/java/com/asksira/loopingviewpagerdemo/MainActivity.java @@ -42,7 +42,7 @@ public void onClick(View v) { viewPager.setIndicatorPageChangeListener(new LoopingViewPager.IndicatorPageChangeListener() { @Override public void onIndicatorProgress(int selectingPosition, float progress) { - indicatorView.setProgress(selectingPosition, progress); +// indicatorView.setProgress(selectingPosition, progress); } @Override diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index cb6e90e..182779e 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -14,7 +14,7 @@ app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" app:isInfinite="true" - app:autoScroll="true" + app:autoScroll="false" app:scrollInterval="2000" app:wrap_content="true"/> diff --git a/loopingviewpager/build.gradle b/loopingviewpager/build.gradle index e0d48a1..c5debd1 100644 --- a/loopingviewpager/build.gradle +++ b/loopingviewpager/build.gradle @@ -8,8 +8,8 @@ android { defaultConfig { minSdkVersion 14 targetSdkVersion 26 - versionCode 1 - versionName "1.0" + versionCode 101 + versionName "1.0.1" testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" @@ -42,7 +42,7 @@ ext { siteUrl = 'https://github.com/siralam/LoopingViewPager' gitUrl = 'https://github.com/siralam/LoopingViewPager.git' - libraryVersion = '1.0.0' + libraryVersion = '1.0.1' developerId = 'siralam' developerName = 'Sira Lam' diff --git a/loopingviewpager/src/main/java/com/asksira/loopingviewpager/LoopingPagerAdapter.java b/loopingviewpager/src/main/java/com/asksira/loopingviewpager/LoopingPagerAdapter.java index 6418442..eecb4be 100644 --- a/loopingviewpager/src/main/java/com/asksira/loopingviewpager/LoopingPagerAdapter.java +++ b/loopingviewpager/src/main/java/com/asksira/loopingviewpager/LoopingPagerAdapter.java @@ -110,6 +110,10 @@ private int getListPosition (int position) { } public int getLastItemPosition() { - return itemList == null ? 0 : itemList.size(); + if (isInfinite) { + return itemList == null ? 0 : itemList.size(); + } else { + return itemList == null ? 0 : itemList.size()-1; + } } } diff --git a/loopingviewpager/src/main/java/com/asksira/loopingviewpager/LoopingViewPager.java b/loopingviewpager/src/main/java/com/asksira/loopingviewpager/LoopingViewPager.java index af3eb2f..479287e 100644 --- a/loopingviewpager/src/main/java/com/asksira/loopingviewpager/LoopingViewPager.java +++ b/loopingviewpager/src/main/java/com/asksira/loopingviewpager/LoopingViewPager.java @@ -6,6 +6,7 @@ import android.support.v4.view.PagerAdapter; import android.support.v4.view.ViewPager; import android.util.AttributeSet; +import android.util.Log; import android.view.View; /** @@ -38,6 +39,7 @@ public void run() { private IndicatorPageChangeListener indicatorPageChangeListener; + private int scrollState = SCROLL_STATE_IDLE; public LoopingViewPager(Context context) { super(context); @@ -52,6 +54,27 @@ public LoopingViewPager(Context context, AttributeSet attrs) { isAutoScroll = a.getBoolean(R.styleable.LoopingViewPager_autoScroll, false); wrapContent = a.getBoolean(R.styleable.LoopingViewPager_wrap_content, true); interval = a.getInt(R.styleable.LoopingViewPager_scrollInterval, 5000); + setPageTransformer(true, new PageTransformer() { + @Override + public void transformPage(View page, float position) { + boolean isToTheRight; + if (position < -1) { + isToTheRight = true; + } else if (position <= 1) { + return; + } else { + isToTheRight = false; + } + + int realPosition = getSelectingIndicatorPosition(isToTheRight); + + if (indicatorPageChangeListener != null && scrollState == SCROLL_STATE_DRAGGING) { + indicatorPageChangeListener.onIndicatorProgress(realPosition, Math.abs(position) - 1); + Log.i("indicator", "Progress: " + realPosition + ", " + String.valueOf(Math.abs(position)-1) + + ", ScrollState: " + scrollState + ", currentPagePosition: " + currentPagePosition); + } + } + }); } finally { a.recycle(); } @@ -92,24 +115,24 @@ private int measureHeight(int measureSpec, View view) { return result; } - protected void init () { + protected void init() { addOnPageChangeListener(new OnPageChangeListener() { @Override public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { - int realPosition = getIndicatorPosition(true); - if (indicatorPageChangeListener != null) indicatorPageChangeListener.onIndicatorProgress(realPosition, positionOffset); } @Override public void onPageSelected(int position) { currentPagePosition = position; - if (indicatorPageChangeListener != null) indicatorPageChangeListener.onIndicatorPageChange(getIndicatorPosition(false)); + if (indicatorPageChangeListener != null) + indicatorPageChangeListener.onIndicatorPageChange(getIndicatorPosition()); autoScrollHandler.removeCallbacks(autoScrollRunnable); autoScrollHandler.postDelayed(autoScrollRunnable, interval); } @Override public void onPageScrollStateChanged(int state) { + scrollState = state; if (!isInfinite) return; //Below are code to achieve infinite scroll. //We silently and immediately flip the item to the first / last. @@ -121,7 +144,7 @@ public void onPageScrollStateChanged(int state) { } int index = getCurrentItem(); if (index == 0) { - setCurrentItem(itemCount-2, false); //Real last item + setCurrentItem(itemCount - 2, false); //Real last item } else if (index == itemCount - 1) { setCurrentItem(1, false); //Real first item } @@ -137,11 +160,11 @@ public void setAdapter(PagerAdapter adapter) { if (isInfinite) setCurrentItem(1, false); } - public void resumeAutoScroll () { + public void resumeAutoScroll() { autoScrollHandler.postDelayed(autoScrollRunnable, interval); } - public void pauseAutoScroll () { + public void pauseAutoScroll() { autoScrollHandler.removeCallbacks(autoScrollRunnable); } @@ -149,34 +172,44 @@ public void pauseAutoScroll () { /** * A method that helps you integrate a ViewPager Indicator. * This method returns the expected position (Starting from 0) of indicators. + * This method should be used after currentPagePosition is updated. */ - public int getIndicatorPosition (boolean notYetSelected) { - if (notYetSelected) { //Selection is in progress. currentPagePosition is not yet updated. - if (!isInfinite) { - return currentPagePosition+1; + public int getIndicatorPosition() { + if (!isInfinite) { + return currentPagePosition; + } else { + if (!(getAdapter() instanceof LoopingPagerAdapter)) return currentPagePosition; + if (currentPagePosition == 0) { //Dummy last item is selected. Indicator should be at the last one + return ((LoopingPagerAdapter) getAdapter()).getListCount()-1; + } else if (currentPagePosition == ((LoopingPagerAdapter) getAdapter()).getLastItemPosition() + 1) { + //Dummy first item is selected. Indicator should be at the first one + return 0; } else { - if (!(getAdapter() instanceof LoopingPagerAdapter)) return currentPagePosition; - if (currentPagePosition == 1) { - return ((LoopingPagerAdapter)getAdapter()).getLastItemPosition() -1; - } else if (currentPagePosition == ((LoopingPagerAdapter)getAdapter()).getLastItemPosition()) { - return 0; - } else { - return currentPagePosition; - } + return currentPagePosition - 1; } - } else { //onPageSelectedIsTriggered. Now currentPagePosition has been updated to the new position. - if (!isInfinite) { - return currentPagePosition; + } + } + + /** + * A method that helps you integrate a ViewPager Indicator. + * This method returns the expected position (Starting from 0) of indicators. + * This method should be used before currentPagePosition is updated, when user is trying to + * select a different page, i.e. onPageScrolled() is triggered. + */ + public int getSelectingIndicatorPosition (boolean isToTheRight) { + int delta = isToTheRight ? 1 : -1; + if (isInfinite) { + if (!(getAdapter() instanceof LoopingPagerAdapter)) return currentPagePosition + delta; + if (currentPagePosition == 1 && !isToTheRight) { //Special case for first page to last page + return ((LoopingPagerAdapter)getAdapter()).getLastItemPosition() -1; + } else if (currentPagePosition == ((LoopingPagerAdapter)getAdapter()).getLastItemPosition() + && isToTheRight) { //Special case for last page to first page + return 0; } else { - if (!(getAdapter() instanceof LoopingPagerAdapter)) return currentPagePosition; - if (currentPagePosition == 0) { - return ((LoopingPagerAdapter)getAdapter()).getLastItemPosition(); - } else if (currentPagePosition == ((LoopingPagerAdapter)getAdapter()).getLastItemPosition()+1) { - return 0; - } else { - return currentPagePosition-1; - } + return currentPagePosition + delta - 1; } + } else { + return currentPagePosition + delta; } } @@ -184,9 +217,9 @@ public int getIndicatorPosition (boolean notYetSelected) { * A method that helps you integrate a ViewPager Indicator. * This method returns the expected count of indicators. */ - public int getIndicatorCount () { + public int getIndicatorCount() { if (getAdapter() instanceof LoopingPagerAdapter) { - return ((LoopingPagerAdapter)getAdapter()).getListCount(); + return ((LoopingPagerAdapter) getAdapter()).getListCount(); } else { return getAdapter().getCount(); } @@ -195,7 +228,7 @@ public int getIndicatorCount () { /** * This function needs to be called if dataSet has changed, - * in order to reset current selected item and currentPagePosition. + * in order to reset current selected item and currentPagePosition and autoPageSelectionLock. */ public void reset() { if (isInfinite) { @@ -207,12 +240,13 @@ public void reset() { } } - public void setIndicatorPageChangeListener (IndicatorPageChangeListener callback) { + public void setIndicatorPageChangeListener(IndicatorPageChangeListener callback) { this.indicatorPageChangeListener = callback; } public interface IndicatorPageChangeListener { void onIndicatorProgress(int selectingPosition, float progress); + void onIndicatorPageChange(int newIndicatorPosition); }