Skip to content

Commit

Permalink
Solved a bug where getSelectinIndicatorPosition() is returning wrong …
Browse files Browse the repository at this point in the history
…value
  • Loading branch information
Sira Lam committed Dec 21, 2017
1 parent ab60f24 commit 52da748
Show file tree
Hide file tree
Showing 7 changed files with 99 additions and 43 deletions.
22 changes: 20 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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

Expand Down
2 changes: 1 addition & 1 deletion app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -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'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion app/src/main/res/layout/activity_main.xml
Original file line number Diff line number Diff line change
Expand Up @@ -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"/>

Expand Down
6 changes: 3 additions & 3 deletions loopingviewpager/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -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"

Expand Down Expand Up @@ -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'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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;

/**
Expand Down Expand Up @@ -38,6 +39,7 @@ public void run() {

private IndicatorPageChangeListener indicatorPageChangeListener;

private int scrollState = SCROLL_STATE_IDLE;

public LoopingViewPager(Context context) {
super(context);
Expand All @@ -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();
}
Expand Down Expand Up @@ -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.
Expand All @@ -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
}
Expand All @@ -137,56 +160,66 @@ 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);
}


/**
* 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;
}
}

/**
* 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();
}
Expand All @@ -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) {
Expand All @@ -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);
}

Expand Down

0 comments on commit 52da748

Please sign in to comment.