Modifying feel of scrolling / overscroll
-Modified overscroll on Workspace -Added overscroll effectiveness curve to PagedView -Modified the feel of scrolling in Workspace, AllApps, and Configure. Made it more sensitive to velocity. Change-Id: I7f705e267a536c742fbb3b6556648bbf993bdd2f
This commit is contained in:
parent
c46b91a832
commit
e0f66b5469
|
@ -36,6 +36,7 @@ import android.view.ViewGroup;
|
|||
import android.view.ViewParent;
|
||||
import android.view.animation.Animation;
|
||||
import android.view.animation.AnimationUtils;
|
||||
import android.view.animation.Interpolator;
|
||||
import android.view.animation.Animation.AnimationListener;
|
||||
import android.widget.Checkable;
|
||||
import android.widget.Scroller;
|
||||
|
@ -55,10 +56,12 @@ public abstract class PagedView extends ViewGroup {
|
|||
// The min drag distance to trigger a page shift (regardless of velocity)
|
||||
private static final int MIN_LENGTH_FOR_MOVE = 200;
|
||||
|
||||
private static final int PAGE_SNAP_ANIMATION_DURATION = 750;
|
||||
private static final int PAGE_SNAP_ANIMATION_DURATION = 550;
|
||||
protected static final float NANOTIME_DIV = 1000000000.0f;
|
||||
|
||||
private static final float OVERSCROLL_DAMP_FACTOR = 0.22f;
|
||||
private static final float OVERSCROLL_DAMP_FACTOR = 0.08f;
|
||||
private static final int MINIMUM_SNAP_VELOCITY = 2200;
|
||||
private static final int MIN_FLING_VELOCITY = 250;
|
||||
|
||||
// the velocity at which a fling gesture will cause us to snap to the next page
|
||||
protected int mSnapVelocity = 500;
|
||||
|
@ -209,7 +212,7 @@ public abstract class PagedView extends ViewGroup {
|
|||
mDirtyPageContent = new ArrayList<Boolean>();
|
||||
mDirtyPageContent.ensureCapacity(32);
|
||||
mPageViewIconCache = new PagedViewIconCache();
|
||||
mScroller = new Scroller(getContext());
|
||||
mScroller = new Scroller(getContext(), new ScrollInterpolator());
|
||||
mCurrentPage = 0;
|
||||
mCenterPagesVertically = true;
|
||||
|
||||
|
@ -827,8 +830,22 @@ public abstract class PagedView extends ViewGroup {
|
|||
return false;
|
||||
}
|
||||
|
||||
// This curve determines how the effect of scrolling over the limits of the page dimishes
|
||||
// as the user pulls further and further from the bounds
|
||||
private float overScrollInfluenceCurve(float f) {
|
||||
f -= 1.0f;
|
||||
return f * f * f + 1.0f;
|
||||
}
|
||||
|
||||
protected void overScroll(float amount) {
|
||||
int overScrollAmount = (int) Math.round(OVERSCROLL_DAMP_FACTOR * amount);
|
||||
int screenSize = getMeasuredWidth();
|
||||
|
||||
float f = (amount / screenSize);
|
||||
|
||||
if (f == 0) return;
|
||||
f = f / (Math.abs(f)) * (overScrollInfluenceCurve(Math.abs(f)));
|
||||
|
||||
int overScrollAmount = (int) Math.round(OVERSCROLL_DAMP_FACTOR * f * screenSize);
|
||||
if (amount < 0) {
|
||||
mScrollX = overScrollAmount;
|
||||
} else {
|
||||
|
@ -902,8 +919,7 @@ public abstract class PagedView extends ViewGroup {
|
|||
|
||||
final int snapVelocity = mSnapVelocity;
|
||||
if ((isSignificantMove && deltaX > 0 ||
|
||||
(isfling && velocityX > snapVelocity)) &&
|
||||
mCurrentPage > 0) {
|
||||
(isfling && velocityX > snapVelocity)) && mCurrentPage > 0) {
|
||||
snapToPageWithVelocity(mCurrentPage - 1, velocityX);
|
||||
} else if ((isSignificantMove && deltaX < 0 ||
|
||||
(isfling && velocityX < -snapVelocity)) &&
|
||||
|
@ -1048,10 +1064,58 @@ public abstract class PagedView extends ViewGroup {
|
|||
snapToPage(getPageNearestToCenterOfScreen(), PAGE_SNAP_ANIMATION_DURATION);
|
||||
}
|
||||
|
||||
private static class ScrollInterpolator implements Interpolator {
|
||||
public ScrollInterpolator() {
|
||||
}
|
||||
|
||||
public float getInterpolation(float t) {
|
||||
t -= 1.0f;
|
||||
return t*t*t*t*t + 1;
|
||||
}
|
||||
}
|
||||
|
||||
// We want the duration of the page snap animation to be influenced by the distance that
|
||||
// the screen has to travel, however, we don't want this duration to be effected in a
|
||||
// purely linear fashion. Instead, we use this method to moderate the effect that the distance
|
||||
// of travel has on the overall snap duration.
|
||||
float distanceInfluenceForSnapDuration(float f) {
|
||||
f -= 0.5f; // center the values about 0.
|
||||
f *= 0.3f * Math.PI / 2.0f;
|
||||
return (float) Math.sin(f);
|
||||
}
|
||||
|
||||
protected void snapToPageWithVelocity(int whichPage, int velocity) {
|
||||
// We ignore velocity in this implementation, but children (e.g. SmoothPagedView)
|
||||
// can use it
|
||||
snapToPage(whichPage);
|
||||
whichPage = Math.max(0, Math.min(whichPage, getChildCount() - 1));
|
||||
int halfScreenSize = getMeasuredWidth() / 2;
|
||||
|
||||
final int newX = getChildOffset(whichPage) - getRelativeChildOffset(whichPage);
|
||||
int delta = newX - mUnboundedScrollX;
|
||||
int duration = 0;
|
||||
|
||||
if (Math.abs(velocity) < MIN_FLING_VELOCITY) {
|
||||
// If the velocity is low enough, then treat this more as an automatic page advance
|
||||
// as opposed to an apparent physical response to flinging
|
||||
snapToPage(whichPage, PAGE_SNAP_ANIMATION_DURATION);
|
||||
return;
|
||||
}
|
||||
|
||||
// Here we compute a "distance" that will be used in the computation of the overall
|
||||
// snap duration. This is a function of the actual distance that needs to be traveled;
|
||||
// we keep this value close to half screen size in order to reduce the variance in snap
|
||||
// duration as a function of the distance the page needs to travel.
|
||||
float distanceRatio = 1.0f * Math.abs(delta) / 2 * halfScreenSize;
|
||||
float distance = halfScreenSize + halfScreenSize *
|
||||
distanceInfluenceForSnapDuration(distanceRatio);
|
||||
|
||||
velocity = Math.abs(velocity);
|
||||
velocity = Math.max(MINIMUM_SNAP_VELOCITY, velocity);
|
||||
|
||||
// we want the page's snap velocity to approximately match the velocity at which the
|
||||
// user flings, so we scale the duration by a value near to the derivative of the scroll
|
||||
// interpolator at zero, ie. 5. We use 6 to make it a little slower.
|
||||
duration = 6 * Math.round(1000 * Math.abs(distance / velocity));
|
||||
|
||||
snapToPage(whichPage, delta, duration);
|
||||
}
|
||||
|
||||
protected void snapToPage(int whichPage) {
|
||||
|
|
|
@ -21,7 +21,6 @@ import android.util.AttributeSet;
|
|||
import android.view.animation.Interpolator;
|
||||
import android.widget.Scroller;
|
||||
|
||||
|
||||
public abstract class SmoothPagedView extends PagedView {
|
||||
private static final float SMOOTHING_SPEED = 0.75f;
|
||||
private static final float SMOOTHING_CONSTANT = (float) (0.016 / Math.log(SMOOTHING_SPEED));
|
||||
|
@ -29,8 +28,8 @@ public abstract class SmoothPagedView extends PagedView {
|
|||
private float mBaseLineFlingVelocity;
|
||||
private float mFlingVelocityInfluence;
|
||||
|
||||
static final int OVERSHOOT_MODE = 0;
|
||||
static final int QUINTIC_MODE = 1;
|
||||
static final int DEFAULT_MODE = 0;
|
||||
static final int X_LARGE_MODE = 1;
|
||||
|
||||
int mScrollMode;
|
||||
|
||||
|
@ -60,16 +59,6 @@ public abstract class SmoothPagedView extends PagedView {
|
|||
}
|
||||
}
|
||||
|
||||
private static class QuinticInterpolator implements Interpolator {
|
||||
public QuinticInterpolator() {
|
||||
}
|
||||
|
||||
public float getInterpolation(float t) {
|
||||
t -= 1.0f;
|
||||
return t*t*t*t*t + 1;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to inflate the Workspace from XML.
|
||||
*
|
||||
|
@ -93,12 +82,12 @@ public abstract class SmoothPagedView extends PagedView {
|
|||
mUsePagingTouchSlop = false;
|
||||
|
||||
// This means that we'll take care of updating the scroll parameter ourselves (we do it
|
||||
// in computeScroll)
|
||||
mDeferScrollUpdate = true;
|
||||
// in computeScroll), we only do this in the OVERSHOOT_MODE, ie. on phones
|
||||
mDeferScrollUpdate = mScrollMode != X_LARGE_MODE;
|
||||
}
|
||||
|
||||
protected int getScrollMode() {
|
||||
return OVERSHOOT_MODE;
|
||||
return DEFAULT_MODE;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -109,26 +98,30 @@ public abstract class SmoothPagedView extends PagedView {
|
|||
super.init();
|
||||
|
||||
mScrollMode = getScrollMode();
|
||||
if (mScrollMode == QUINTIC_MODE) {
|
||||
mBaseLineFlingVelocity = 700.0f;
|
||||
mFlingVelocityInfluence = 0.8f;
|
||||
mScrollInterpolator = new QuinticInterpolator();
|
||||
} else { // QUINTIC_MODE
|
||||
if (mScrollMode == DEFAULT_MODE) {
|
||||
mBaseLineFlingVelocity = 2500.0f;
|
||||
mFlingVelocityInfluence = 0.4f;
|
||||
mScrollInterpolator = new WorkspaceOvershootInterpolator();
|
||||
mScroller = new Scroller(getContext(), mScrollInterpolator);
|
||||
}
|
||||
mScroller = new Scroller(getContext(), mScrollInterpolator);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void snapToDestination() {
|
||||
snapToPageWithVelocity(getPageNearestToCenterOfScreen(), 0);
|
||||
if (mScrollMode == X_LARGE_MODE) {
|
||||
super.snapToDestination();
|
||||
} else {
|
||||
snapToPageWithVelocity(getPageNearestToCenterOfScreen(), 0);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void snapToPageWithVelocity(int whichPage, int velocity) {
|
||||
snapToPageWithVelocity(whichPage, 0, true);
|
||||
if (mScrollMode == X_LARGE_MODE) {
|
||||
super.snapToPageWithVelocity(whichPage, velocity);
|
||||
} else {
|
||||
snapToPageWithVelocity(whichPage, 0, true);
|
||||
}
|
||||
}
|
||||
|
||||
private void snapToPageWithVelocity(int whichPage, int velocity, boolean settle) {
|
||||
|
@ -139,23 +132,16 @@ public abstract class SmoothPagedView extends PagedView {
|
|||
final int screenDelta = Math.max(1, Math.abs(whichPage - mCurrentPage));
|
||||
final int newX = getChildOffset(whichPage) - getRelativeChildOffset(whichPage);
|
||||
final int delta = newX - mUnboundedScrollX;
|
||||
int duration;
|
||||
if (mScrollMode == OVERSHOOT_MODE) {
|
||||
duration = (screenDelta + 1) * 100;
|
||||
} else { // QUINTIC_MODE
|
||||
duration = Math.round(Math.abs(delta) * 0.6f);
|
||||
}
|
||||
int duration = (screenDelta + 1) * 100;
|
||||
|
||||
if (!mScroller.isFinished()) {
|
||||
mScroller.abortAnimation();
|
||||
}
|
||||
|
||||
if (mScrollMode == OVERSHOOT_MODE) {
|
||||
if (settle) {
|
||||
((WorkspaceOvershootInterpolator) mScrollInterpolator).setDistance(screenDelta);
|
||||
} else {
|
||||
((WorkspaceOvershootInterpolator) mScrollInterpolator).disableSettle();
|
||||
}
|
||||
if (settle) {
|
||||
((WorkspaceOvershootInterpolator) mScrollInterpolator).setDistance(screenDelta);
|
||||
} else {
|
||||
((WorkspaceOvershootInterpolator) mScrollInterpolator).disableSettle();
|
||||
}
|
||||
|
||||
velocity = Math.abs(velocity);
|
||||
|
@ -170,26 +156,33 @@ public abstract class SmoothPagedView extends PagedView {
|
|||
|
||||
@Override
|
||||
protected void snapToPage(int whichPage) {
|
||||
snapToPageWithVelocity(whichPage, 0, false);
|
||||
if (mScrollMode == X_LARGE_MODE) {
|
||||
super.snapToPage(whichPage);
|
||||
} else {
|
||||
snapToPageWithVelocity(whichPage, 0, false);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void computeScroll() {
|
||||
boolean scrollComputed = computeScrollHelper();
|
||||
if (mScrollMode == X_LARGE_MODE) {
|
||||
super.computeScroll();
|
||||
} else {
|
||||
boolean scrollComputed = computeScrollHelper();
|
||||
|
||||
if (!scrollComputed && mTouchState == TOUCH_STATE_SCROLLING) {
|
||||
final float now = System.nanoTime() / NANOTIME_DIV;
|
||||
final float e = (float) Math.exp((now - mSmoothingTime) / SMOOTHING_CONSTANT);
|
||||
if (!scrollComputed && mTouchState == TOUCH_STATE_SCROLLING) {
|
||||
final float now = System.nanoTime() / NANOTIME_DIV;
|
||||
final float e = (float) Math.exp((now - mSmoothingTime) / SMOOTHING_CONSTANT);
|
||||
|
||||
final float dx = mTouchX - mUnboundedScrollX;
|
||||
scrollTo(Math.round(mUnboundedScrollX + dx * e), mScrollY);
|
||||
mSmoothingTime = now;
|
||||
final float dx = mTouchX - mUnboundedScrollX;
|
||||
scrollTo(Math.round(mUnboundedScrollX + dx * e), mScrollY);
|
||||
mSmoothingTime = now;
|
||||
|
||||
// Keep generating points as long as we're more than 1px away from the target
|
||||
if (dx > 1.f || dx < -1.f) {
|
||||
invalidate();
|
||||
// Keep generating points as long as we're more than 1px away from the target
|
||||
if (dx > 1.f || dx < -1.f) {
|
||||
invalidate();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -109,6 +109,7 @@ public class Workspace extends SmoothPagedView
|
|||
private Drawable mBackground;
|
||||
private float mBackgroundAlpha = 0;
|
||||
private float mOverScrollMaxBackgroundAlpha = 0.0f;
|
||||
private int mOverScrollPageIndex = -1;
|
||||
|
||||
private final WallpaperManager mWallpaperManager;
|
||||
|
||||
|
@ -268,9 +269,9 @@ public class Workspace extends SmoothPagedView
|
|||
@Override
|
||||
protected int getScrollMode() {
|
||||
if (LauncherApplication.isScreenXLarge()) {
|
||||
return SmoothPagedView.QUINTIC_MODE;
|
||||
return SmoothPagedView.X_LARGE_MODE;
|
||||
} else {
|
||||
return SmoothPagedView.OVERSHOOT_MODE;
|
||||
return SmoothPagedView.DEFAULT_MODE;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -516,6 +517,7 @@ public class Workspace extends SmoothPagedView
|
|||
mAnimOnPageEndMoving = null;
|
||||
}
|
||||
mOverScrollMaxBackgroundAlpha = 0.0f;
|
||||
mOverScrollPageIndex = -1;
|
||||
mPageMoving = false;
|
||||
}
|
||||
|
||||
|
@ -653,7 +655,7 @@ public class Workspace extends SmoothPagedView
|
|||
}
|
||||
|
||||
float overScrollBackgroundAlphaInterpolator(float r) {
|
||||
float threshold = 0.1f;
|
||||
float threshold = 0.08f;
|
||||
|
||||
if (r > mOverScrollMaxBackgroundAlpha) {
|
||||
mOverScrollMaxBackgroundAlpha = r;
|
||||
|
@ -664,23 +666,6 @@ public class Workspace extends SmoothPagedView
|
|||
return Math.min(r / threshold, 1.0f);
|
||||
}
|
||||
|
||||
protected void overScroll(float amount) {
|
||||
final int lastChildIndex = getChildCount() - 1;
|
||||
|
||||
CellLayout cl;
|
||||
if (amount < 0) {
|
||||
cl = (CellLayout) getChildAt(0);
|
||||
} else {
|
||||
cl = (CellLayout) getChildAt(lastChildIndex);
|
||||
}
|
||||
|
||||
final int totalDistance = cl.getMeasuredWidth() + mPageSpacing;
|
||||
float r = 1.0f * amount / totalDistance;
|
||||
float rotation = -WORKSPACE_ROTATION * r;
|
||||
cl.setBackgroundAlphaMultiplier(overScrollBackgroundAlphaInterpolator(Math.abs(r)));
|
||||
cl.setRotationY(rotation);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void screenScrolled(int screenCenter) {
|
||||
final int halfScreenSize = getMeasuredWidth() / 2;
|
||||
|
@ -696,7 +681,18 @@ public class Workspace extends SmoothPagedView
|
|||
scrollProgress = Math.min(scrollProgress, 1.0f);
|
||||
scrollProgress = Math.max(scrollProgress, -1.0f);
|
||||
|
||||
cl.setBackgroundAlphaMultiplier(backgroundAlphaInterpolator(Math.abs(scrollProgress)));
|
||||
// If the current page (i) is being overscrolled, we use a different
|
||||
// set of rules for setting the background alpha multiplier.
|
||||
if ((mScrollX < 0 && i == 0) || (mScrollX > mMaxScrollX &&
|
||||
i == getChildCount() -1 )) {
|
||||
cl.setBackgroundAlphaMultiplier(
|
||||
overScrollBackgroundAlphaInterpolator(Math.abs(scrollProgress)));
|
||||
mOverScrollPageIndex = i;
|
||||
} else if (mOverScrollPageIndex != i) {
|
||||
cl.setBackgroundAlphaMultiplier(
|
||||
backgroundAlphaInterpolator(Math.abs(scrollProgress)));
|
||||
|
||||
}
|
||||
|
||||
float rotation = WORKSPACE_ROTATION * scrollProgress;
|
||||
float translationX = getOffsetXForRotation(rotation, cl.getWidth(), cl.getHeight());
|
||||
|
|
Loading…
Reference in New Issue