Adapt Lollipop EdgeEffect
This commit is contained in:
1 parent
3523503d08
commit
132d866dd9
4 files changed
+151
-212
No files matched your search
@@ -1,11 +1,11 @@
|
||||
/*
|
||||
* Copyright (C) 2011 The Android Open Source Project
|
||||
* Copyright 2015 Hippo Seven
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
@@ -16,87 +16,45 @@
|
||||
|
||||
package com.hippo.ehviewer.gallery.ui;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Rect;
|
||||
import android.view.animation.AnimationUtils;
|
||||
import android.view.animation.DecelerateInterpolator;
|
||||
import android.view.animation.Interpolator;
|
||||
|
||||
import com.hippo.ehviewer.R;
|
||||
import com.hippo.ehviewer.gallery.glrenderer.GLCanvas;
|
||||
import com.hippo.ehviewer.gallery.glrenderer.ResourceTexture;
|
||||
|
||||
// This is copied from android.widget.EdgeEffect with some small modifications:
|
||||
// (1) Copy the images (overscroll_{edge|glow}.png) to local resources.
|
||||
// (2) Use "GLCanvas" instead of "Canvas" for draw()'s parameter.
|
||||
// (3) Use a private Drawable class (which inherits from ResourceTexture)
|
||||
// instead of android.graphics.drawable.Drawable to hold the images.
|
||||
// The private Drawable class is used to translate original Canvas calls to
|
||||
// corresponding GLCanvas calls.
|
||||
|
||||
/**
|
||||
* This class performs the graphical effect used at the edges of scrollable widgets
|
||||
* when the user scrolls beyond the content bounds in 2D space.
|
||||
*
|
||||
* <p>EdgeEffect is stateful. Custom widgets using EdgeEffect should create an
|
||||
* instance for each edge that should show the effect, feed it input data using
|
||||
* the methods {@link #onAbsorb(int)}, {@link #onPull(float)}, and {@link #onRelease()},
|
||||
* and draw the effect using {@link #draw(GLCanvas)} in the widget's overridden
|
||||
* {@link android.view.View#draw(Canvas)} method. If {@link #isFinished()} returns
|
||||
* false after drawing, the edge effect's animation is not yet complete and the widget
|
||||
* should schedule another drawing pass to continue the animation.</p>
|
||||
*
|
||||
* <p>When drawing, widgets should draw their main content and child views first,
|
||||
* usually by invoking <code>super.draw(canvas)</code> from an overridden <code>draw</code>
|
||||
* method. (This will invoke onDraw and dispatch drawing to child views as needed.)
|
||||
* The edge effect may then be drawn on top of the view's content using the
|
||||
* {@link #draw(GLCanvas)} method.</p>
|
||||
*/
|
||||
public class EdgeEffect {
|
||||
@SuppressWarnings("unused")
|
||||
private static final String TAG = "EdgeEffect";
|
||||
|
||||
// Time it will take the effect to fully recede in ms
|
||||
private static final int RECEDE_TIME = 1000;
|
||||
private static final int RECEDE_TIME = 600;
|
||||
|
||||
// Time it will take before a pulled glow begins receding in ms
|
||||
private static final int PULL_TIME = 167;
|
||||
|
||||
// Time it will take in ms for a pulled glow to decay to partial strength before release
|
||||
private static final int PULL_DECAY_TIME = 1000;
|
||||
private static final int PULL_DECAY_TIME = 2000;
|
||||
|
||||
private static final float MAX_ALPHA = 0.8f;
|
||||
private static final float HELD_EDGE_ALPHA = 0.7f;
|
||||
private static final float HELD_EDGE_SCALE_Y = 0.5f;
|
||||
private static final float HELD_GLOW_ALPHA = 0.5f;
|
||||
private static final float HELD_GLOW_SCALE_Y = 0.5f;
|
||||
private static final float MAX_ALPHA = 0.5f;
|
||||
|
||||
private static final float MAX_GLOW_HEIGHT = 4.f;
|
||||
private static final float MAX_GLOW_SCALE = 2.f;
|
||||
|
||||
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;
|
||||
// Maximum velocity, clamps at this value
|
||||
private static final int MAX_VELOCITY = 10000;
|
||||
|
||||
private static final float EPSILON = 0.001f;
|
||||
|
||||
private final Drawable mEdge;
|
||||
private final Drawable mGlow;
|
||||
private int mWidth;
|
||||
private int mHeight;
|
||||
private final int MIN_WIDTH = 300;
|
||||
private final int mMinWidth;
|
||||
private static final double ANGLE = Math.PI / 6;
|
||||
private static final float SIN = (float) Math.sin(ANGLE);
|
||||
private static final float COS = (float) Math.cos(ANGLE);
|
||||
|
||||
private float mEdgeAlpha;
|
||||
private float mEdgeScaleY;
|
||||
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;
|
||||
@@ -113,31 +71,26 @@ 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;
|
||||
private static final float PULL_DISTANCE_ALPHA_GLOW_FACTOR = 0.8f;
|
||||
|
||||
// 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 = 16;
|
||||
private static final int VELOCITY_GLOW_FACTOR = 6;
|
||||
|
||||
private int mState = STATE_IDLE;
|
||||
|
||||
private float mPullDistance;
|
||||
|
||||
private final Rect mBounds = new Rect();
|
||||
private int mColor;
|
||||
private float mRadius;
|
||||
private float mBaseGlowScale;
|
||||
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) {
|
||||
mEdge = new Drawable(context, R.drawable.overscroll_edge);
|
||||
mGlow = new Drawable(context, R.drawable.overscroll_glow);
|
||||
|
||||
mMinWidth = (int) (context.getResources().getDisplayMetrics().density * MIN_WIDTH + 0.5f);
|
||||
public EdgeEffect(int color) {
|
||||
mColor = color;
|
||||
mInterpolator = new DecelerateInterpolator();
|
||||
}
|
||||
|
||||
@@ -148,8 +101,17 @@ 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.75f / SIN;
|
||||
final float y = COS * r;
|
||||
final float h = r - y;
|
||||
final float or = height * 0.75f / SIN;
|
||||
final float oy = COS * or;
|
||||
final float oh = or - oy;
|
||||
|
||||
mRadius = r;
|
||||
mBaseGlowScale = h > 0 ? Math.min(oh / h, 1.f) : 1.f;
|
||||
|
||||
mBounds.set(mBounds.left, mBounds.top, width, (int) Math.min(height, h));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -177,17 +139,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) {
|
||||
final long now = AnimationTime.get();
|
||||
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;
|
||||
|
||||
@@ -195,30 +178,20 @@ 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));
|
||||
|
||||
final float absdd = Math.abs(deltaDistance);
|
||||
mGlowAlpha = mGlowAlphaStart = Math.min(MAX_ALPHA,
|
||||
mGlowAlpha +
|
||||
(Math.abs(deltaDistance) * PULL_DISTANCE_ALPHA_GLOW_FACTOR));
|
||||
mGlowAlpha + (absdd * PULL_DISTANCE_ALPHA_GLOW_FACTOR));
|
||||
|
||||
float glowChange = Math.abs(deltaDistance);
|
||||
if (deltaDistance > 0 && mPullDistance < 0) {
|
||||
glowChange = -glowChange;
|
||||
}
|
||||
if (mPullDistance == 0) {
|
||||
mGlowScaleY = 0;
|
||||
mGlowScaleY = mGlowScaleYStart = 0;
|
||||
} else {
|
||||
final float scale = Math.max(0, 1 - 1 /
|
||||
(float) Math.sqrt(Math.abs(mPullDistance) * mBounds.height()) - 0.3f) / 0.7f;
|
||||
|
||||
mGlowScaleY = mGlowScaleYStart = scale;
|
||||
}
|
||||
|
||||
// Do not allow glow to get larger than MAX_GLOW_HEIGHT.
|
||||
mGlowScaleY = mGlowScaleYStart = Math.min(MAX_GLOW_HEIGHT, Math.max(
|
||||
0, mGlowScaleY + glowChange * PULL_DISTANCE_GLOW_FACTOR));
|
||||
|
||||
mEdgeAlphaFinish = mEdgeAlpha;
|
||||
mEdgeScaleYFinish = mEdgeScaleY;
|
||||
mGlowAlphaFinish = mGlowAlpha;
|
||||
mGlowScaleYFinish = mGlowScaleY;
|
||||
}
|
||||
@@ -237,17 +210,13 @@ 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;
|
||||
|
||||
mStartTime = AnimationTime.get();
|
||||
mStartTime = AnimationUtils.currentAnimationTimeMillis();
|
||||
mDuration = RECEDE_TIME;
|
||||
}
|
||||
|
||||
@@ -263,37 +232,44 @@ public class EdgeEffect {
|
||||
*/
|
||||
public void onAbsorb(int velocity) {
|
||||
mState = STATE_ABSORB;
|
||||
velocity = Math.max(MIN_VELOCITY, Math.abs(velocity));
|
||||
velocity = Math.min(Math.max(MIN_VELOCITY, Math.abs(velocity)), MAX_VELOCITY);
|
||||
|
||||
mStartTime = AnimationTime.get();
|
||||
mDuration = 0.1f + (velocity * 0.03f);
|
||||
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.5f;
|
||||
mGlowScaleYStart = 0.f;
|
||||
mGlowAlphaStart = 0.3f;
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the color of this edge effect in argb.
|
||||
*
|
||||
* @param color Color in argb
|
||||
*/
|
||||
public void setColor(int color) {
|
||||
mColor = color;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the color of this edge effect in argb.
|
||||
* @return The color of this edge effect in argb
|
||||
*/
|
||||
public int getColor() {
|
||||
return mColor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Draw into the provided canvas. Assumes that the canvas has been rotated
|
||||
@@ -308,97 +284,77 @@ public class EdgeEffect {
|
||||
public boolean draw(GLCanvas canvas) {
|
||||
update();
|
||||
|
||||
final int edgeHeight = mEdge.getIntrinsicHeight();
|
||||
final int edgeWidth = mEdge.getIntrinsicWidth();
|
||||
final int glowHeight = mGlow.getIntrinsicHeight();
|
||||
final int glowWidth = mGlow.getIntrinsicWidth();
|
||||
canvas.save();
|
||||
|
||||
mGlow.setAlpha((int) (Math.max(0, Math.min(mGlowAlpha, 1)) * 255));
|
||||
final float centerX = mBounds.centerX();
|
||||
final float centerY = mBounds.height() - mRadius;
|
||||
|
||||
int glowBottom = (int) Math.min(
|
||||
glowHeight * mGlowScaleY * glowHeight/ glowWidth * 0.6f,
|
||||
glowHeight * 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);
|
||||
canvas.translate(-centerX, 0f);
|
||||
canvas.scale(1.f, Math.min(mGlowScaleY, 1.f) * mBaseGlowScale, 0);
|
||||
canvas.translate(centerX, 0f);
|
||||
|
||||
final float displacement = Math.max(0, Math.min(mDisplacement, 1.f)) - 0.5f;
|
||||
float translateX = mBounds.width() * displacement / 2;
|
||||
|
||||
canvas.translate(translateX, 0);
|
||||
canvas.fillOval(centerX, centerY, mRadius, mRadius, mColor);
|
||||
canvas.restore();
|
||||
|
||||
boolean oneLastFrame = false;
|
||||
if (mState == STATE_RECEDE && mGlowScaleY == 0) {
|
||||
mState = STATE_IDLE;
|
||||
oneLastFrame = true;
|
||||
}
|
||||
|
||||
mGlow.draw(canvas);
|
||||
return mState != STATE_IDLE || oneLastFrame;
|
||||
}
|
||||
|
||||
mEdge.setAlpha((int) (Math.max(0, Math.min(mEdgeAlpha, 1)) * 255));
|
||||
|
||||
int edgeBottom = (int) (edgeHeight * 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);
|
||||
}
|
||||
mEdge.draw(canvas);
|
||||
|
||||
return mState != STATE_IDLE;
|
||||
/**
|
||||
* 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 int getMaxHeight() {
|
||||
return (int) (mBounds.height() * MAX_GLOW_SCALE + 0.5f);
|
||||
}
|
||||
|
||||
private void update() {
|
||||
final long time = AnimationTime.get();
|
||||
final long time = AnimationUtils.currentAnimationTimeMillis();
|
||||
final float t = Math.min((time - mStartTime) / mDuration, 1.f);
|
||||
|
||||
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) {
|
||||
case STATE_ABSORB:
|
||||
mState = STATE_RECEDE;
|
||||
mStartTime = AnimationTime.get();
|
||||
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;
|
||||
case STATE_PULL:
|
||||
mState = STATE_PULL_DECAY;
|
||||
mStartTime = AnimationTime.get();
|
||||
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:
|
||||
@@ -407,37 +363,4 @@ public class EdgeEffect {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static class Drawable extends ResourceTexture {
|
||||
private Rect mBounds = new Rect();
|
||||
private int mAlpha = 255;
|
||||
|
||||
public Drawable(Context context, int resId) {
|
||||
super(context, resId);
|
||||
}
|
||||
|
||||
public int getIntrinsicWidth() {
|
||||
return getWidth();
|
||||
}
|
||||
|
||||
public int getIntrinsicHeight() {
|
||||
return getHeight();
|
||||
}
|
||||
|
||||
public void setBounds(int left, int top, int right, int bottom) {
|
||||
mBounds.set(left, top, right, bottom);
|
||||
}
|
||||
|
||||
public void setAlpha(int alpha) {
|
||||
mAlpha = alpha;
|
||||
}
|
||||
|
||||
public void draw(GLCanvas canvas) {
|
||||
canvas.save(GLCanvas.SAVE_FLAG_ALPHA);
|
||||
canvas.multiplyAlpha(mAlpha / 255.0f);
|
||||
Rect b = mBounds;
|
||||
draw(canvas, b.left, b.top, b.width(), b.height());
|
||||
canvas.restore();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,11 +1,11 @@
|
||||
/*
|
||||
* Copyright (C) 2011 The Android Open Source Project
|
||||
* Copyright 2015 Hippo Seven
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
@@ -17,11 +17,12 @@
|
||||
package com.hippo.ehviewer.gallery.ui;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.TypedArray;
|
||||
import android.opengl.Matrix;
|
||||
|
||||
import com.hippo.ehviewer.R;
|
||||
import com.hippo.ehviewer.gallery.glrenderer.GLCanvas;
|
||||
|
||||
// EdgeView draws EdgeEffect (blue glow) at four sides of the view.
|
||||
public class EdgeView extends GLView {
|
||||
@SuppressWarnings("unused")
|
||||
private static final String TAG = "EdgeView";
|
||||
@@ -44,8 +45,14 @@ public class EdgeView extends GLView {
|
||||
private float[] mMatrix = new float[4 * 16];
|
||||
|
||||
public EdgeView(Context context) {
|
||||
final TypedArray a = context.obtainStyledAttributes(
|
||||
R.styleable.Theme);
|
||||
final int themeColor = a.getColor(
|
||||
R.styleable.Theme_colorPrimary, 0xff666666);
|
||||
a.recycle();
|
||||
int color = (themeColor & 0xffffff) | 0x33000000;
|
||||
for (int i = 0; i < 4; i++) {
|
||||
mEffect[i] = new EdgeEffect(context);
|
||||
mEffect[i] = new EdgeEffect(color);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -100,7 +107,7 @@ public class EdgeView extends GLView {
|
||||
|
||||
// Called when the content is pulled away from the edge.
|
||||
// offset is in pixels. direction is one of {TOP, LEFT, BOTTOM, RIGHT}.
|
||||
public void onPull(int offset, int direction) {
|
||||
public void onPull(float offset, int direction) {
|
||||
int fullLength = ((direction & 1) == 0) ? getWidth() : getHeight();
|
||||
mEffect[direction].onPull((float)offset / fullLength);
|
||||
if (!mEffect[direction].isFinished()) {
|
||||
@@ -108,6 +115,15 @@ public class EdgeView extends GLView {
|
||||
}
|
||||
}
|
||||
|
||||
public void onPull(float offset, float position, int direction) {
|
||||
int fullLength = ((direction & 1) == 0) ? getWidth() : getHeight();
|
||||
int fullPosition = ((direction & 1) == 0) ? getHeight() : getWidth();
|
||||
mEffect[direction].onPull(offset / fullLength, position / fullPosition);
|
||||
if (!mEffect[direction].isFinished()) {
|
||||
invalidate();
|
||||
}
|
||||
}
|
||||
|
||||
// Call when the object is released after being pulled.
|
||||
public void onRelease() {
|
||||
boolean more = false;
|
||||
|
||||
@@ -245,13 +245,13 @@ public class GalleryView extends GLView implements GestureRecognizer.Listener {
|
||||
if (mFirstShownIndex > 0) {
|
||||
scrollToPage(mFirstShownIndex - 1);
|
||||
} else {
|
||||
mEdgeView.onPull(getWidth() * 2, EdgeView.LEFT);
|
||||
mEdgeView.onPull(getWidth() * 2, (int) y, EdgeView.LEFT);
|
||||
}
|
||||
} else {
|
||||
if (mFirstShownIndex < mAdapter.getPages() - 1) {
|
||||
scrollToPage(mFirstShownIndex + 1);
|
||||
} else {
|
||||
mEdgeView.onPull(getWidth() * 2, EdgeView.RIGHT);
|
||||
mEdgeView.onPull(getWidth() * 2, (int) y, EdgeView.RIGHT);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -352,7 +352,7 @@ public class GalleryView extends GLView implements GestureRecognizer.Listener {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onScroll(float dx, float dy, float totalX, float totalY) {
|
||||
public boolean onScroll(float dx, float dy, float totalX, float totalY, float x, float y) {
|
||||
if (mScale) {
|
||||
return false;
|
||||
}
|
||||
@@ -387,14 +387,14 @@ public class GalleryView extends GLView implements GestureRecognizer.Listener {
|
||||
mEdgeView.onRelease();
|
||||
}
|
||||
mDeltaX += remain;
|
||||
mEdgeView.onPull(-mDeltaX, EdgeView.LEFT);
|
||||
mEdgeView.onPull(-mDeltaX, y, EdgeView.LEFT);
|
||||
} else {
|
||||
if (mDeltaX < 0) {
|
||||
mDeltaX = 0;
|
||||
mEdgeView.onRelease();
|
||||
}
|
||||
mDeltaX += remain;
|
||||
mEdgeView.onPull(mDeltaX, EdgeView.RIGHT);
|
||||
mEdgeView.onPull(mDeltaX, y, EdgeView.RIGHT);
|
||||
}
|
||||
|
||||
} else if (mMode == Mode.TOP_TO_BOTTOM) {
|
||||
|
||||
@@ -34,7 +34,7 @@ public class GestureRecognizer {
|
||||
boolean onSingleTapConfirmed(float x, float y);
|
||||
boolean onDoubleTap(float x, float y);
|
||||
boolean onDoubleTapConfirmed(float x, float y);
|
||||
boolean onScroll(float dx, float dy, float totalX, float totalY);
|
||||
boolean onScroll(float dx, float dy, float totalX, float totalY, float x, float y);
|
||||
boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY);
|
||||
boolean onScaleBegin(float focusX, float focusY);
|
||||
boolean onScale(float focusX, float focusY, float scale);
|
||||
@@ -109,7 +109,7 @@ public class GestureRecognizer {
|
||||
public boolean onScroll(
|
||||
MotionEvent e1, MotionEvent e2, float dx, float dy) {
|
||||
return mListener.onScroll(
|
||||
dx, dy, e2.getX() - e1.getX(), e2.getY() - e1.getY());
|
||||
dx, dy, e2.getX() - e1.getX(), e2.getY() - e1.getY(), e2.getX(), e2.getY());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
Reference in new issue
Block a user