summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--api/current.txt2
-rw-r--r--core/java/android/widget/AbsListView.java71
-rw-r--r--core/java/android/widget/EdgeEffect.java221
-rw-r--r--core/java/android/widget/HorizontalScrollView.java6
-rw-r--r--core/java/android/widget/ScrollView.java6
-rw-r--r--core/res/res/values/attrs.xml4
6 files changed, 140 insertions, 170 deletions
diff --git a/api/current.txt b/api/current.txt
index f51f79b..380d641 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -34886,9 +34886,11 @@ package android.widget {
ctor public EdgeEffect(android.content.Context);
method public boolean draw(android.graphics.Canvas);
method public void finish();
+ method public int getMaxHeight();
method public boolean isFinished();
method public void onAbsorb(int);
method public void onPull(float);
+ method public void onPull(float, float);
method public void onRelease();
method public void setSize(int, int);
}
diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java
index f4cd5fc..565ea13 100644
--- a/core/java/android/widget/AbsListView.java
+++ b/core/java/android/widget/AbsListView.java
@@ -3267,7 +3267,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
}
}
- private boolean startScrollIfNeeded(int y, MotionEvent vtev) {
+ private boolean startScrollIfNeeded(int x, int y, MotionEvent vtev) {
// Check if we have moved far enough that it looks more like a
// scroll than a tap
final int deltaY = y - mMotionY;
@@ -3296,14 +3296,14 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
if (parent != null) {
parent.requestDisallowInterceptTouchEvent(true);
}
- scrollIfNeeded(y, vtev);
+ scrollIfNeeded(x, y, vtev);
return true;
}
return false;
}
- private void scrollIfNeeded(int y, MotionEvent vtev) {
+ private void scrollIfNeeded(int x, int y, MotionEvent vtev) {
int rawDeltaY = y - mMotionY;
if (dispatchNestedPreScroll(0, rawDeltaY, mScrollConsumed, mScrollOffset)) {
rawDeltaY -= mScrollConsumed[1];
@@ -3384,33 +3384,39 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
vtev.offsetLocation(0, mScrollOffset[1]);
}
} else {
- overScrollBy(0, overscroll, 0, mScrollY, 0, 0,
- 0, mOverscrollDistance, true);
- if (Math.abs(mOverscrollDistance) == Math.abs(mScrollY)) {
- // Don't allow overfling if we're at the edge.
- if (mVelocityTracker != null) {
- mVelocityTracker.clear();
- }
+ final boolean atOverscrollEdge = overScrollBy(0, overscroll,
+ 0, mScrollY, 0, 0, 0, mOverscrollDistance, true);
+
+ if (atOverscrollEdge && mVelocityTracker != null) {
+ // Don't allow overfling if we're at the edge
+ mVelocityTracker.clear();
}
final int overscrollMode = getOverScrollMode();
if (overscrollMode == OVER_SCROLL_ALWAYS ||
(overscrollMode == OVER_SCROLL_IF_CONTENT_SCROLLS &&
!contentFits())) {
- mDirection = 0; // Reset when entering overscroll.
- mTouchMode = TOUCH_MODE_OVERSCROLL;
- if (deltaY > 0) {
- mEdgeGlowTop.onPull((float) overscroll / getHeight());
+ if (!atOverscrollEdge) {
+ mDirection = 0; // Reset when entering overscroll.
+ mTouchMode = TOUCH_MODE_OVERSCROLL;
+ }
+ if (incrementalDeltaY > 0) {
+ mEdgeGlowTop.onPull((float) overscroll / getHeight(),
+ (float) x / getWidth());
if (!mEdgeGlowBottom.isFinished()) {
mEdgeGlowBottom.onRelease();
}
- invalidate(mEdgeGlowTop.getBounds(false));
- } else if (deltaY < 0) {
- mEdgeGlowBottom.onPull((float) overscroll / getHeight());
+ invalidate(0, 0, getWidth(),
+ mEdgeGlowTop.getMaxHeight() + getPaddingTop());
+ } else if (incrementalDeltaY < 0) {
+ mEdgeGlowBottom.onPull((float) overscroll / getHeight(),
+ 1.f - (float) x / getWidth());
if (!mEdgeGlowTop.isFinished()) {
mEdgeGlowTop.onRelease();
}
- invalidate(mEdgeGlowBottom.getBounds(true));
+ invalidate(0, getHeight() - getPaddingBottom() -
+ mEdgeGlowBottom.getMaxHeight(), getWidth(),
+ getHeight());
}
}
}
@@ -3445,17 +3451,22 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
(overscrollMode == OVER_SCROLL_IF_CONTENT_SCROLLS &&
!contentFits())) {
if (rawDeltaY > 0) {
- mEdgeGlowTop.onPull((float) overScrollDistance / getHeight());
+ mEdgeGlowTop.onPull((float) overScrollDistance / getHeight(),
+ (float) x / getWidth());
if (!mEdgeGlowBottom.isFinished()) {
mEdgeGlowBottom.onRelease();
}
- invalidate(mEdgeGlowTop.getBounds(false));
+ invalidate(0, 0, getWidth(),
+ mEdgeGlowTop.getMaxHeight() + getPaddingTop());
} else if (rawDeltaY < 0) {
- mEdgeGlowBottom.onPull((float) overScrollDistance / getHeight());
+ mEdgeGlowBottom.onPull((float) overScrollDistance / getHeight(),
+ 1.f - (float) x / getWidth());
if (!mEdgeGlowTop.isFinished()) {
mEdgeGlowTop.onRelease();
}
- invalidate(mEdgeGlowBottom.getBounds(true));
+ invalidate(0, getHeight() - getPaddingBottom() -
+ mEdgeGlowBottom.getMaxHeight(), getWidth(),
+ getHeight());
}
}
}
@@ -3703,7 +3714,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
case TOUCH_MODE_DONE_WAITING:
// Check if we have moved far enough that it looks more like a
// scroll than a tap. If so, we'll enter scrolling mode.
- if (startScrollIfNeeded(y, vtev)) {
+ if (startScrollIfNeeded((int) ev.getX(pointerIndex), y, vtev)) {
break;
}
// Otherwise, check containment within list bounds. If we're
@@ -3723,7 +3734,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
break;
case TOUCH_MODE_SCROLL:
case TOUCH_MODE_OVERSCROLL:
- scrollIfNeeded(y, vtev);
+ scrollIfNeeded((int) ev.getX(pointerIndex), y, vtev);
break;
}
}
@@ -4022,8 +4033,8 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
canvas.translate(leftPadding, edgeY);
mEdgeGlowTop.setSize(width, getHeight());
if (mEdgeGlowTop.draw(canvas)) {
- mEdgeGlowTop.setPosition(leftPadding, edgeY);
- invalidate(mEdgeGlowTop.getBounds(false));
+ invalidate(0, 0, getWidth(),
+ mEdgeGlowTop.getMaxHeight() + getPaddingTop());
}
canvas.restoreToCount(restoreCount);
}
@@ -4040,9 +4051,9 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
canvas.rotate(180, width, 0);
mEdgeGlowBottom.setSize(width, height);
if (mEdgeGlowBottom.draw(canvas)) {
- // Account for the rotation
- mEdgeGlowBottom.setPosition(edgeX + width, edgeY);
- invalidate(mEdgeGlowBottom.getBounds(true));
+ invalidate(0, getHeight() - getPaddingBottom() -
+ mEdgeGlowBottom.getMaxHeight(), getWidth(),
+ getHeight());
}
canvas.restoreToCount(restoreCount);
}
@@ -4161,7 +4172,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
final int y = (int) ev.getY(pointerIndex);
initVelocityTrackerIfNotExists();
mVelocityTracker.addMovement(ev);
- if (startScrollIfNeeded(y, null)) {
+ if (startScrollIfNeeded((int) ev.getX(pointerIndex), y, null)) {
return true;
}
break;
diff --git a/core/java/android/widget/EdgeEffect.java b/core/java/android/widget/EdgeEffect.java
index fa37443..83fbe8f 100644
--- a/core/java/android/widget/EdgeEffect.java
+++ b/core/java/android/widget/EdgeEffect.java
@@ -16,7 +16,14 @@
package android.widget;
+import android.content.res.TypedArray;
+import android.graphics.Paint;
+import android.graphics.PorterDuff;
+import android.graphics.PorterDuffXfermode;
import android.graphics.Rect;
+import android.graphics.RectF;
+import android.graphics.Xfermode;
+import android.util.Log;
import com.android.internal.R;
import android.content.Context;
@@ -59,12 +66,10 @@ public class EdgeEffect {
private static final int PULL_DECAY_TIME = 1000;
private static final float MAX_ALPHA = 1.f;
- private static final float HELD_EDGE_SCALE_Y = 0.5f;
- private static final float MAX_GLOW_HEIGHT = 4.f;
+ private static final float MAX_GLOW_HEIGHT = 1.5f;
- private static final float PULL_GLOW_BEGIN = 1.f;
- private static final float PULL_EDGE_BEGIN = 0.6f;
+ private static final float PULL_GLOW_BEGIN = 0.f;
// Minimum velocity that will be absorbed
private static final int MIN_VELOCITY = 100;
@@ -73,24 +78,11 @@ public class EdgeEffect {
private static final float EPSILON = 0.001f;
- private final Drawable mEdge;
- private final Drawable mGlow;
- private int mWidth;
- private int mHeight;
- private int mX;
- private int mY;
- private static final int MIN_WIDTH = 300;
- private final int mMinWidth;
-
- private float mEdgeAlpha;
- private float mEdgeScaleY;
+ private static final float SIN_45 = (float) Math.sin(Math.PI / 4);
+
private float mGlowAlpha;
private float mGlowScaleY;
- private float mEdgeAlphaStart;
- private float mEdgeAlphaFinish;
- private float mEdgeScaleYStart;
- private float mEdgeScaleYFinish;
private float mGlowAlphaStart;
private float mGlowAlphaFinish;
private float mGlowScaleYStart;
@@ -107,16 +99,11 @@ public class EdgeEffect {
private static final int STATE_RECEDE = 3;
private static final int STATE_PULL_DECAY = 4;
- // How much dragging should effect the height of the edge image.
- // Number determined by user testing.
- private static final int PULL_DISTANCE_EDGE_FACTOR = 7;
-
// How much dragging should effect the height of the glow image.
// Number determined by user testing.
private static final int PULL_DISTANCE_GLOW_FACTOR = 7;
private static final float PULL_DISTANCE_ALPHA_GLOW_FACTOR = 1.1f;
- private static final int VELOCITY_EDGE_FACTOR = 8;
private static final int VELOCITY_GLOW_FACTOR = 12;
private int mState = STATE_IDLE;
@@ -124,30 +111,26 @@ public class EdgeEffect {
private float mPullDistance;
private final Rect mBounds = new Rect();
-
- private final int mEdgeHeight;
- private final int mGlowHeight;
- private final int mGlowWidth;
- private final int mMaxEffectHeight;
+ private final RectF mArcRect = new RectF();
+ private final Paint mPaint = new Paint();
+ private float mRadius;
+ private float mDisplacement = 0.5f;
+ private float mTargetDisplacement = 0.5f;
/**
* Construct a new EdgeEffect with a theme appropriate for the provided context.
* @param context Context used to provide theming and resource information for the EdgeEffect
*/
public EdgeEffect(Context context) {
- final Resources res = context.getResources();
- mEdge = context.getDrawable(R.drawable.overscroll_edge);
- mGlow = context.getDrawable(R.drawable.overscroll_glow);
-
- mEdgeHeight = mEdge.getIntrinsicHeight();
- mGlowHeight = mGlow.getIntrinsicHeight();
- mGlowWidth = mGlow.getIntrinsicWidth();
-
- mMaxEffectHeight = (int) (Math.min(
- mGlowHeight * MAX_GLOW_HEIGHT * mGlowHeight / mGlowWidth * 0.6f,
- mGlowHeight * MAX_GLOW_HEIGHT) + 0.5f);
-
- mMinWidth = (int) (res.getDisplayMetrics().density * MIN_WIDTH + 0.5f);
+ mPaint.setAntiAlias(true);
+ final TypedArray a = context.obtainStyledAttributes(
+ com.android.internal.R.styleable.EdgeEffect);
+ final int themeColor = a.getColor(
+ com.android.internal.R.styleable.EdgeEffect_colorPrimaryLight, 0xff666666);
+ a.recycle();
+ mPaint.setColor((themeColor & 0xffffff) | 0x66000000);
+ mPaint.setStyle(Paint.Style.FILL);
+ mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_ATOP));
mInterpolator = new DecelerateInterpolator();
}
@@ -158,20 +141,12 @@ public class EdgeEffect {
* @param height Effect height in pixels
*/
public void setSize(int width, int height) {
- mWidth = width;
- mHeight = height;
- }
+ final float r = width * 0.5f / SIN_45;
+ final float y = SIN_45 * r;
+ final float h = r - y;
+ mRadius = r;
- /**
- * Set the position of this edge effect in pixels. This position is
- * only used by {@link #getBounds(boolean)}.
- *
- * @param x The position of the edge effect on the X axis
- * @param y The position of the edge effect on the Y axis
- */
- void setPosition(int x, int y) {
- mX = x;
- mY = y;
+ mBounds.set(mBounds.left, mBounds.top, width, (int) Math.min(height, h));
}
/**
@@ -199,17 +174,38 @@ public class EdgeEffect {
* The host view should always {@link android.view.View#invalidate()} after this
* and draw the results accordingly.
*
+ * <p>Views using EdgeEffect should favor {@link #onPull(float, float)} when the displacement
+ * of the pull point is known.</p>
+ *
* @param deltaDistance Change in distance since the last call. Values may be 0 (no change) to
* 1.f (full length of the view) or negative values to express change
* back toward the edge reached to initiate the effect.
*/
public void onPull(float deltaDistance) {
+ onPull(deltaDistance, 0.5f);
+ }
+
+ /**
+ * A view should call this when content is pulled away from an edge by the user.
+ * This will update the state of the current visual effect and its associated animation.
+ * The host view should always {@link android.view.View#invalidate()} after this
+ * and draw the results accordingly.
+ *
+ * @param deltaDistance Change in distance since the last call. Values may be 0 (no change) to
+ * 1.f (full length of the view) or negative values to express change
+ * back toward the edge reached to initiate the effect.
+ * @param displacement The displacement from the starting side of the effect of the point
+ * initiating the pull. In the case of touch this is the finger position.
+ * Values may be from 0-1.
+ */
+ public void onPull(float deltaDistance, float displacement) {
final long now = AnimationUtils.currentAnimationTimeMillis();
+ mTargetDisplacement = displacement;
if (mState == STATE_PULL_DECAY && now - mStartTime < mDuration) {
return;
}
if (mState != STATE_PULL) {
- mGlowScaleY = PULL_GLOW_BEGIN;
+ mGlowScaleY = Math.max(PULL_GLOW_BEGIN, mGlowScaleY);
}
mState = STATE_PULL;
@@ -217,15 +213,10 @@ public class EdgeEffect {
mDuration = PULL_TIME;
mPullDistance += deltaDistance;
- float distance = Math.abs(mPullDistance);
-
- mEdgeAlpha = mEdgeAlphaStart = Math.max(PULL_EDGE_BEGIN, Math.min(distance, MAX_ALPHA));
- mEdgeScaleY = mEdgeScaleYStart = Math.max(
- HELD_EDGE_SCALE_Y, Math.min(distance * PULL_DISTANCE_EDGE_FACTOR, 1.f));
mGlowAlpha = mGlowAlphaStart = Math.min(MAX_ALPHA,
mGlowAlpha +
- (Math.abs(deltaDistance) * PULL_DISTANCE_ALPHA_GLOW_FACTOR));
+ (Math.abs(deltaDistance) * PULL_DISTANCE_ALPHA_GLOW_FACTOR));
float glowChange = Math.abs(deltaDistance);
if (deltaDistance > 0 && mPullDistance < 0) {
@@ -239,8 +230,6 @@ public class EdgeEffect {
mGlowScaleY = mGlowScaleYStart = Math.min(MAX_GLOW_HEIGHT, Math.max(
0, mGlowScaleY + glowChange * PULL_DISTANCE_GLOW_FACTOR));
- mEdgeAlphaFinish = mEdgeAlpha;
- mEdgeScaleYFinish = mEdgeScaleY;
mGlowAlphaFinish = mGlowAlpha;
mGlowScaleYFinish = mGlowScaleY;
}
@@ -259,13 +248,9 @@ public class EdgeEffect {
}
mState = STATE_RECEDE;
- mEdgeAlphaStart = mEdgeAlpha;
- mEdgeScaleYStart = mEdgeScaleY;
mGlowAlphaStart = mGlowAlpha;
mGlowScaleYStart = mGlowScaleY;
- mEdgeAlphaFinish = 0.f;
- mEdgeScaleYFinish = 0.f;
mGlowAlphaFinish = 0.f;
mGlowScaleYFinish = 0.f;
@@ -290,30 +275,21 @@ public class EdgeEffect {
mStartTime = AnimationUtils.currentAnimationTimeMillis();
mDuration = 0.15f + (velocity * 0.02f);
- // The edge should always be at least partially visible, regardless
- // of velocity.
- mEdgeAlphaStart = 0.f;
- mEdgeScaleY = mEdgeScaleYStart = 0.f;
// The glow depends more on the velocity, and therefore starts out
// nearly invisible.
mGlowAlphaStart = 0.3f;
- mGlowScaleYStart = 0.f;
+ mGlowScaleYStart = Math.max(mGlowScaleY, 0.f);
- // Factor the velocity by 8. Testing on device shows this works best to
- // reflect the strength of the user's scrolling.
- mEdgeAlphaFinish = Math.max(0, Math.min(velocity * VELOCITY_EDGE_FACTOR, 1));
- // Edge should never get larger than the size of its asset.
- mEdgeScaleYFinish = Math.max(
- HELD_EDGE_SCALE_Y, Math.min(velocity * VELOCITY_EDGE_FACTOR, 1.f));
// Growth for the size of the glow should be quadratic to properly
// respond
// to a user's scrolling speed. The faster the scrolling speed, the more
// intense the effect should be for both the size and the saturation.
- mGlowScaleYFinish = Math.min(0.025f + (velocity * (velocity / 100) * 0.00015f), 1.75f);
+ mGlowScaleYFinish = Math.min(0.025f + (velocity * (velocity / 100) * 0.00015f) / 2, 1.f);
// Alpha should change for the glow as well as size.
mGlowAlphaFinish = Math.max(
mGlowAlphaStart, Math.min(velocity * VELOCITY_GLOW_FACTOR * .00001f, MAX_ALPHA));
+ mTargetDisplacement = 0.5f;
}
@@ -330,52 +306,42 @@ public class EdgeEffect {
public boolean draw(Canvas canvas) {
update();
- mGlow.setAlpha((int) (Math.max(0, Math.min(mGlowAlpha, 1)) * 255));
-
- int glowBottom = (int) Math.min(
- mGlowHeight * mGlowScaleY * mGlowHeight / mGlowWidth * 0.6f,
- mGlowHeight * MAX_GLOW_HEIGHT);
- if (mWidth < mMinWidth) {
- // Center the glow and clip it.
- int glowLeft = (mWidth - mMinWidth)/2;
- mGlow.setBounds(glowLeft, 0, mWidth - glowLeft, glowBottom);
- } else {
- // Stretch the glow to fit.
- mGlow.setBounds(0, 0, mWidth, glowBottom);
- }
+ final int count = canvas.save();
- mGlow.draw(canvas);
+ final float y = mBounds.height();
+ final float centerY = y - mRadius;
+ final float centerX = mBounds.centerX();
+ mArcRect.set(centerX - mRadius, centerY - mRadius, centerX + mRadius, centerY + mRadius);
+ canvas.scale(1.f, Math.min(mGlowScaleY, 1.f), centerX, 0);
- mEdge.setAlpha((int) (Math.max(0, Math.min(mEdgeAlpha, 1)) * 255));
-
- int edgeBottom = (int) (mEdgeHeight * mEdgeScaleY);
- if (mWidth < mMinWidth) {
- // Center the edge and clip it.
- int edgeLeft = (mWidth - mMinWidth)/2;
- mEdge.setBounds(edgeLeft, 0, mWidth - edgeLeft, edgeBottom);
- } else {
- // Stretch the edge to fit.
- mEdge.setBounds(0, 0, mWidth, edgeBottom);
+ final float displacement = Math.max(0, Math.min(mDisplacement, 1.f)) - 0.5f;
+ float translateX = mBounds.width() * displacement;
+ float translateY = 0;
+ if (mGlowScaleY > 1.f) {
+ translateY = (mGlowScaleY - 1.f) * mBounds.height();
}
- mEdge.draw(canvas);
-
- if (mState == STATE_RECEDE && glowBottom == 0 && edgeBottom == 0) {
+ canvas.clipRect(Float.MIN_VALUE, mBounds.top,
+ Float.MAX_VALUE, Float.MAX_VALUE);
+ canvas.translate(translateX, translateY);
+ canvas.drawArc(mArcRect, 0, 180, true, mPaint);
+ canvas.restoreToCount(count);
+
+ boolean oneLastFrame = false;
+ if (mState == STATE_RECEDE && mGlowScaleY == 0) {
mState = STATE_IDLE;
+ oneLastFrame = true;
}
- return mState != STATE_IDLE;
+ return mState != STATE_IDLE || oneLastFrame;
}
/**
- * Returns the bounds of the edge effect.
- *
- * @hide
+ * Return the maximum height that the edge effect will be drawn at given the original
+ * {@link #setSize(int, int) input size}.
+ * @return The maximum height of the edge effect
*/
- public Rect getBounds(boolean reverse) {
- mBounds.set(0, 0, mWidth, mMaxEffectHeight);
- mBounds.offset(mX, mY - (reverse ? mMaxEffectHeight : 0));
-
- return mBounds;
+ public int getMaxHeight() {
+ return (int) (mBounds.height() * MAX_GLOW_HEIGHT + 0.5f);
}
private void update() {
@@ -384,10 +350,9 @@ public class EdgeEffect {
final float interp = mInterpolator.getInterpolation(t);
- mEdgeAlpha = mEdgeAlphaStart + (mEdgeAlphaFinish - mEdgeAlphaStart) * interp;
- mEdgeScaleY = mEdgeScaleYStart + (mEdgeScaleYFinish - mEdgeScaleYStart) * interp;
mGlowAlpha = mGlowAlphaStart + (mGlowAlphaFinish - mGlowAlphaStart) * interp;
mGlowScaleY = mGlowScaleYStart + (mGlowScaleYFinish - mGlowScaleYStart) * interp;
+ mDisplacement = (mDisplacement + mTargetDisplacement) / 2;
if (t >= 1.f - EPSILON) {
switch (mState) {
@@ -396,14 +361,10 @@ public class EdgeEffect {
mStartTime = AnimationUtils.currentAnimationTimeMillis();
mDuration = RECEDE_TIME;
- mEdgeAlphaStart = mEdgeAlpha;
- mEdgeScaleYStart = mEdgeScaleY;
mGlowAlphaStart = mGlowAlpha;
mGlowScaleYStart = mGlowScaleY;
- // After absorb, the glow and edge should fade to nothing.
- mEdgeAlphaFinish = 0.f;
- mEdgeScaleYFinish = 0.f;
+ // After absorb, the glow should fade to nothing.
mGlowAlphaFinish = 0.f;
mGlowScaleYFinish = 0.f;
break;
@@ -412,26 +373,14 @@ public class EdgeEffect {
mStartTime = AnimationUtils.currentAnimationTimeMillis();
mDuration = PULL_DECAY_TIME;
- mEdgeAlphaStart = mEdgeAlpha;
- mEdgeScaleYStart = mEdgeScaleY;
mGlowAlphaStart = mGlowAlpha;
mGlowScaleYStart = mGlowScaleY;
- // After pull, the glow and edge should fade to nothing.
- mEdgeAlphaFinish = 0.f;
- mEdgeScaleYFinish = 0.f;
+ // After pull, the glow should fade to nothing.
mGlowAlphaFinish = 0.f;
mGlowScaleYFinish = 0.f;
break;
case STATE_PULL_DECAY:
- // When receding, we want edge to decrease more slowly
- // than the glow.
- float factor = mGlowScaleYFinish != 0 ? 1
- / (mGlowScaleYFinish * mGlowScaleYFinish)
- : Float.MAX_VALUE;
- mEdgeScaleY = mEdgeScaleYStart +
- (mEdgeScaleYFinish - mEdgeScaleYStart) *
- interp * factor;
mState = STATE_RECEDE;
break;
case STATE_RECEDE:
diff --git a/core/java/android/widget/HorizontalScrollView.java b/core/java/android/widget/HorizontalScrollView.java
index 25d4f42..0c65c50 100644
--- a/core/java/android/widget/HorizontalScrollView.java
+++ b/core/java/android/widget/HorizontalScrollView.java
@@ -616,12 +616,14 @@ public class HorizontalScrollView extends FrameLayout {
if (canOverscroll) {
final int pulledToX = oldX + deltaX;
if (pulledToX < 0) {
- mEdgeGlowLeft.onPull((float) deltaX / getWidth());
+ mEdgeGlowLeft.onPull((float) deltaX / getWidth(),
+ 1.f - ev.getY(activePointerIndex) / getHeight());
if (!mEdgeGlowRight.isFinished()) {
mEdgeGlowRight.onRelease();
}
} else if (pulledToX > range) {
- mEdgeGlowRight.onPull((float) deltaX / getWidth());
+ mEdgeGlowRight.onPull((float) deltaX / getWidth(),
+ ev.getY(activePointerIndex) / getHeight());
if (!mEdgeGlowLeft.isFinished()) {
mEdgeGlowLeft.onRelease();
}
diff --git a/core/java/android/widget/ScrollView.java b/core/java/android/widget/ScrollView.java
index 0fa75a6..fd04890 100644
--- a/core/java/android/widget/ScrollView.java
+++ b/core/java/android/widget/ScrollView.java
@@ -669,12 +669,14 @@ public class ScrollView extends FrameLayout {
} else if (canOverscroll) {
final int pulledToY = oldY + deltaY;
if (pulledToY < 0) {
- mEdgeGlowTop.onPull((float) deltaY / getHeight());
+ mEdgeGlowTop.onPull((float) deltaY / getHeight(),
+ ev.getX(activePointerIndex) / getWidth());
if (!mEdgeGlowBottom.isFinished()) {
mEdgeGlowBottom.onRelease();
}
} else if (pulledToY > range) {
- mEdgeGlowBottom.onPull((float) deltaY / getHeight());
+ mEdgeGlowBottom.onPull((float) deltaY / getHeight(),
+ 1.f - ev.getX(activePointerIndex) / getWidth());
if (!mEdgeGlowTop.isFinished()) {
mEdgeGlowTop.onRelease();
}
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 28e75e6..7a6832e 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -6605,4 +6605,8 @@
<attr name="layout_gravity" />
</declare-styleable>
+ <!-- Used as a filter array on the theme to pull out only the EdgeEffect-relevant bits. -->
+ <declare-styleable name="EdgeEffect">
+ <attr name="colorPrimaryLight" />
+ </declare-styleable>
</resources>