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 7d7c7c3..ba9a5f5 100644 --- a/library/src/main/java/com/heinrichreimersoftware/materialintro/app/IntroActivity.java +++ b/library/src/main/java/com/heinrichreimersoftware/materialintro/app/IntroActivity.java @@ -8,9 +8,7 @@ import android.annotation.TargetApi; import android.app.ActivityManager; import android.content.Intent; -import android.content.pm.ActivityInfo; import android.content.res.ColorStateList; -import android.content.res.Configuration; import android.content.res.Resources; import android.content.res.TypedArray; import android.graphics.Bitmap; @@ -76,6 +74,8 @@ public class IntroActivity extends AppCompatActivity implements IntroNavigation private static final String KEY_BUTTON_CTA_VISIBLE = "com.heinrichreimersoftware.materialintro.app.IntroActivity.KEY_BUTTON_CTA_VISIBLE"; + private boolean activityCreated = false; + //Settings constants @IntDef({BUTTON_NEXT_FUNCTION_NEXT, BUTTON_NEXT_FUNCTION_NEXT_FINISH}) @Retention(RetentionPolicy.SOURCE) @@ -144,8 +144,6 @@ public class IntroActivity extends AppCompatActivity implements IntroNavigation protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - lockOrientation(); - pageScrollInterpolator = AnimationUtils.loadInterpolator(this, android.R.interpolator.accelerate_decelerate); pageScrollDuration = getResources().getInteger(android.R.integer.config_shortAnimTime); @@ -181,6 +179,8 @@ protected void onCreate(Bundle savedInstanceState) { @Override protected void onPostCreate(Bundle savedInstanceState) { super.onPostCreate(savedInstanceState); + activityCreated = true; + updateTaskDescription(); updateButtonNextDrawable(); updateButtonBackDrawable(); @@ -242,10 +242,11 @@ public Intent onSendActivityResult(int result) { @Override protected void onDestroy() { - if (isAutoplaying()) + if (isAutoplaying()) { cancelAutoplay(); + } - unlockOrientation(); + activityCreated = false; super.onDestroy(); } @@ -466,12 +467,7 @@ public boolean goToFirstSlide() { private void performButtonBackPress() { if (buttonBackFunction == BUTTON_BACK_FUNCTION_SKIP) { - int count = getCount(); - int endPosition = pager.getCurrentItem(); - while (endPosition < count && canGoForward(endPosition, true)) { - endPosition++; - } - smoothScrollPagerTo(endPosition); + goToSlide(getCount()); } else if (buttonBackFunction == BUTTON_BACK_FUNCTION_BACK) { previousSlide(); } @@ -941,26 +937,6 @@ private void updateButtonBackDrawable() { } } - private void lockOrientation() { - int orientation; - int rotation = getResources().getConfiguration().orientation; - switch (rotation) { - case Configuration.ORIENTATION_LANDSCAPE: - orientation = ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE; - break; - case Configuration.ORIENTATION_PORTRAIT: - default: - orientation = ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT; - break; - } - - setRequestedOrientation(orientation); - } - - private void unlockOrientation() { - setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED); - } - @SuppressWarnings("unused") public void autoplay(@IntRange(from = 1) long delay, @IntRange(from = -1) int repeatCount) { autoplayCounter = repeatCount; @@ -1399,12 +1375,18 @@ public void setPageTransformer(boolean reverseDrawingOrder, ViewPager.PageTransf } public void notifyDataSetChanged() { + if (!activityCreated) { + // Don't notify any listener until the activity is created + return; + } + int position = this.position; pager.setAdapter(adapter); pager.setCurrentItem(position); - if (finishIfNeeded()) + if (finishIfNeeded()) { return; + } updateTaskDescription(); updateButtonBackDrawable(); @@ -1419,8 +1401,9 @@ public void onPageScrolled(int position, float positionOffset, int positionOffse IntroActivity.this.position = (int) Math.floor(position + positionOffset); IntroActivity.this.positionOffset = (((position + positionOffset) % 1) + 1) % 1; - if (finishIfNeeded()) + if (finishIfNeeded()) { return; + } //Lock while scrolling a slide near its edges to lock (uncommon) multiple page swipes if (Math.abs(positionOffset) < 0.1f) { @@ -1442,12 +1425,7 @@ public void onPageSelected(int position) { private class ButtonCtaClickListener implements View.OnClickListener { @Override public void onClick(View v) { - int count = getCount(); - int endPosition = pager.getCurrentItem(); - while (endPosition < count && canGoForward(endPosition, true)) { - endPosition++; - } - smoothScrollPagerTo(endPosition); + goToSlide(getCount()); } } } diff --git a/library/src/main/java/com/heinrichreimersoftware/materialintro/view/SwipeBlockableViewPager.java b/library/src/main/java/com/heinrichreimersoftware/materialintro/view/SwipeBlockableViewPager.java index a72549c..08a8621 100644 --- a/library/src/main/java/com/heinrichreimersoftware/materialintro/view/SwipeBlockableViewPager.java +++ b/library/src/main/java/com/heinrichreimersoftware/materialintro/view/SwipeBlockableViewPager.java @@ -1,35 +1,31 @@ package com.heinrichreimersoftware.materialintro.view; import android.content.Context; -import android.support.annotation.IntDef; +import android.os.Bundle; +import android.os.Parcelable; import android.support.v4.view.ViewPager; import android.util.AttributeSet; import android.view.MotionEvent; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; - public class SwipeBlockableViewPager extends ViewPager { - @IntDef({SWIPE_DIRECTION_LEFT, SWIPE_DIRECTION_NONE, SWIPE_DIRECTION_RIGHT}) - @Retention(RetentionPolicy.SOURCE) - private @interface SwipeDirection { - } - - private static final int SWIPE_DIRECTION_LEFT = 1; - private static final int SWIPE_DIRECTION_NONE = 0; + private static final int SWIPE_LOCK_THRESHOLD = 0; + private static final int SWIPE_UNLOCK_THRESHOLD = 0; - private static final int SWIPE_DIRECTION_RIGHT = -1; + private static final String STATE_SUPER = "SUPER"; + private static final String STATE_SWIPE_RIGHT_ENABLED = "SWIPE_RIGHT_ENABLED"; + private static final String STATE_SWIPE_LEFT_ENABLED = "SWIPE_LEFT_ENABLED"; - private static final int SWIPE_THRESHOLD = 0; + private static final int INVALID_POINTER_ID = -1; - private float initialX; + private int activePointerId = INVALID_POINTER_ID; + private float lastTouchX; private boolean swipeRightEnabled = true; - private boolean swipeLeftEnabled = true; - private boolean locked = false; + private boolean lockedLeft = false; + private boolean lockedRight = false; public SwipeBlockableViewPager(Context context) { super(context); @@ -58,51 +54,105 @@ public boolean onInterceptTouchEvent(MotionEvent event) { } private boolean handleTouchEvent(MotionEvent event) { - if (getSwipeDirection(event) == SWIPE_DIRECTION_RIGHT && !swipeRightEnabled) { - if (!locked) { - locked = true; - updatePosition(); + boolean allowTouch = false; + final int action = event.getAction(); + switch (action & MotionEvent.ACTION_MASK) { + case MotionEvent.ACTION_DOWN: { + lastTouchX = event.getX(); + + // Save the ID of this pointer + activePointerId = event.getPointerId(0); + + break; } - return false; - } - else if (getSwipeDirection(event) == SWIPE_DIRECTION_LEFT && !swipeLeftEnabled) { - if (!locked) { - locked = true; - updatePosition(); + + case MotionEvent.ACTION_MOVE: { + // Find the index of the active pointer and fetch its position + final int pointerIndex = event.findPointerIndex(activePointerId); + final float x = event.getX(pointerIndex); + + final float dx = x - lastTouchX; + + if (dx > 0) { + // Swiped right + if (!swipeRightEnabled && Math.abs(dx) > SWIPE_LOCK_THRESHOLD) { + lockedRight = true; + } + if (!lockedRight) { + allowTouch = true; + if (Math.abs(dx) > SWIPE_UNLOCK_THRESHOLD) { + lockedLeft = false; + } + } + } else if (dx < 0) { + // Swiped left + if (!swipeLeftEnabled && Math.abs(dx) > SWIPE_LOCK_THRESHOLD) { + lockedLeft = true; + } + if (!lockedLeft) { + allowTouch = true; + if (Math.abs(dx) > SWIPE_UNLOCK_THRESHOLD) { + lockedRight = false; + } + } + } + + lastTouchX = x; + + invalidate(); + break; } - return false; - } - locked = false; - return true; - } - private void updatePosition() { - int currentItem = getCurrentItem(); - scrollTo(currentItem * getWidth(), getScrollY()); - setCurrentItem(currentItem); - } + case MotionEvent.ACTION_UP: { + activePointerId = INVALID_POINTER_ID; + lockedLeft = false; + lockedRight = false; + break; + } + + case MotionEvent.ACTION_CANCEL: { + activePointerId = INVALID_POINTER_ID; + lockedLeft = false; + lockedRight = false; + break; + } - @SwipeDirection - public int getSwipeDirection(MotionEvent event) { - if (event.getAction() == MotionEvent.ACTION_DOWN) { - initialX = event.getX(); - return SWIPE_DIRECTION_NONE; + case MotionEvent.ACTION_POINTER_UP: { + // Extract the index of the pointer that left the touch sensor + final int pointerIndex = (action & MotionEvent.ACTION_POINTER_INDEX_MASK) + >> MotionEvent.ACTION_POINTER_INDEX_SHIFT; + final int pointerId = event.getPointerId(pointerIndex); + if (pointerId == activePointerId) { + // This was our active pointer going up. Choose a new + // active pointer and adjust accordingly. + final int newPointerIndex = pointerIndex == 0 ? 1 : 0; + lastTouchX = event.getX(newPointerIndex); + activePointerId = event.getPointerId(newPointerIndex); + } + break; + } } - if (event.getAction() == MotionEvent.ACTION_MOVE || - event.getAction() == MotionEvent.ACTION_UP) { - float distanceX = event.getX() - initialX; + return (!lockedLeft && !lockedRight) || allowTouch; + } - if (SWIPE_THRESHOLD > Math.abs(distanceX)) { - return SWIPE_DIRECTION_NONE; - } - if (distanceX > 0) { - return SWIPE_DIRECTION_RIGHT; - } else if (distanceX < 0) { - return SWIPE_DIRECTION_LEFT; - } + @Override + public void onRestoreInstanceState(Parcelable state) { + if (state instanceof Bundle) { + Bundle bundle = (Bundle) state; + swipeRightEnabled = bundle.getBoolean(STATE_SWIPE_RIGHT_ENABLED, true); + swipeLeftEnabled = bundle.getBoolean(STATE_SWIPE_LEFT_ENABLED, true); + state = bundle.getParcelable(STATE_SUPER); } + super.onRestoreInstanceState(state); + } - return SWIPE_DIRECTION_NONE; + @Override + public Parcelable onSaveInstanceState() { + Bundle bundle = new Bundle(4); + bundle.putParcelable(STATE_SUPER, super.onSaveInstanceState()); + bundle.putBoolean(STATE_SWIPE_RIGHT_ENABLED, swipeRightEnabled); + bundle.putBoolean(STATE_SWIPE_LEFT_ENABLED, swipeLeftEnabled); + return bundle; } }