Drop edgeEffect
* This md2 but not md3 * We have no reason to reinvent the wheel
This commit is contained in:
1 parent
2e74222244
commit
0ced054631
8 files changed
+7
-774
No files matched your search
@@ -353,7 +353,6 @@ public class GalleryActivity extends EhActivity implements SeekBar.OnSeekBarChan
|
||||
.setStartPosition(Settings.getStartPosition())
|
||||
.setStartPage(startPage)
|
||||
.setBackgroundColor(ResourcesKt.resolveColor(getTheme(), android.R.attr.colorBackground))
|
||||
.setEdgeColor(ResourcesKt.resolveColor(getTheme(), R.attr.colorEdgeEffect) & 0xffffff | 0x33000000)
|
||||
.setPagerInterval(Settings.getShowPageInterval() ? resources.getDimensionPixelOffset(R.dimen.gallery_pager_interval) : 0)
|
||||
.setScrollInterval(Settings.getShowPageInterval() ? resources.getDimensionPixelOffset(R.dimen.gallery_scroll_interval) : 0)
|
||||
.setPageMinHeight(resources.getDimensionPixelOffset(R.dimen.gallery_page_min_height))
|
||||
|
||||
@@ -36,7 +36,6 @@ import com.hippo.glview.util.GalleryUtils;
|
||||
import com.hippo.glview.view.AnimationTime;
|
||||
import com.hippo.glview.view.GLRoot;
|
||||
import com.hippo.glview.view.GLView;
|
||||
import com.hippo.glview.widget.GLEdgeView;
|
||||
import com.hippo.glview.widget.GLProgressView;
|
||||
import com.hippo.glview.widget.GLTextureView;
|
||||
import com.hippo.yorozuya.MathUtils;
|
||||
@@ -94,7 +93,6 @@ public final class GalleryView extends GLView implements GestureRecognizer.Liste
|
||||
private final GestureRecognizer mGestureRecognizer;
|
||||
@Nullable
|
||||
private final Listener mListener;
|
||||
private final GLEdgeView mEdgeView;
|
||||
private final Pool<GalleryPageView> mGalleryPageViewPool = new Pool<>(5);
|
||||
private final int mBackgroundColor;
|
||||
private final int mPageMinHeight;
|
||||
@@ -144,7 +142,6 @@ public final class GalleryView extends GLView implements GestureRecognizer.Liste
|
||||
mAdapter.setGalleryView(this);
|
||||
mListener = build.mListener;
|
||||
mGestureRecognizer = new GestureRecognizer(mContext, this);
|
||||
mEdgeView = new GLEdgeView(build.mEdgeColor);
|
||||
|
||||
mLayoutMode = build.mLayoutMode;
|
||||
mScaleMode = build.mScaleMode;
|
||||
@@ -291,7 +288,6 @@ public final class GalleryView extends GLView implements GestureRecognizer.Liste
|
||||
@Override
|
||||
public void onAttachToRoot(GLRoot root) {
|
||||
super.onAttachToRoot(root);
|
||||
mEdgeView.onAttachToRoot(root);
|
||||
postMethod(METHOD_ON_ATTACH_TO_ROOT);
|
||||
}
|
||||
|
||||
@@ -305,7 +301,6 @@ public final class GalleryView extends GLView implements GestureRecognizer.Liste
|
||||
}
|
||||
|
||||
super.onDetachFromRoot();
|
||||
mEdgeView.onDetachFromRoot();
|
||||
}
|
||||
|
||||
public int getLayoutMode() {
|
||||
@@ -342,10 +337,6 @@ public final class GalleryView extends GLView implements GestureRecognizer.Liste
|
||||
return true;
|
||||
}
|
||||
|
||||
GLEdgeView getEdgeView() {
|
||||
return mEdgeView;
|
||||
}
|
||||
|
||||
String getDefaultErrorStr() {
|
||||
return mDefaultErrorString;
|
||||
}
|
||||
@@ -482,10 +473,7 @@ public final class GalleryView extends GLView implements GestureRecognizer.Liste
|
||||
|
||||
@Override
|
||||
protected void onLayout(boolean changeSize, int left, int top, int right, int bottom) {
|
||||
mEdgeView.layout(left, top, right, bottom);
|
||||
|
||||
fill();
|
||||
|
||||
if (changeSize) {
|
||||
int width = right - left;
|
||||
int height = bottom - top;
|
||||
@@ -861,7 +849,6 @@ public final class GalleryView extends GLView implements GestureRecognizer.Liste
|
||||
mWillFill = false;
|
||||
|
||||
super.render(canvas);
|
||||
mEdgeView.render(canvas);
|
||||
|
||||
int newCurrentIndex;
|
||||
if (mLayoutManager != null) {
|
||||
@@ -1054,11 +1041,6 @@ public final class GalleryView extends GLView implements GestureRecognizer.Liste
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setEdgeColor(int edgeColor) {
|
||||
mEdgeColor = edgeColor;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setPagerInterval(int pagerInterval) {
|
||||
mPagerInterval = pagerInterval;
|
||||
return this;
|
||||
|
||||
@@ -25,9 +25,7 @@ import androidx.annotation.IntDef;
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import com.hippo.glview.anim.Animation;
|
||||
import com.hippo.glview.anim.FloatAnimation;
|
||||
import com.hippo.glview.view.GLView;
|
||||
import com.hippo.glview.widget.GLEdgeView;
|
||||
import com.hippo.glview.widget.GLProgressView;
|
||||
import com.hippo.glview.widget.GLTextureView;
|
||||
import com.hippo.yorozuya.AnimationUtils;
|
||||
@@ -54,7 +52,6 @@ class PagerLayoutManager extends GalleryView.LayoutManager {
|
||||
private final SmoothScroller mSmoothScroller;
|
||||
private final PageFling mPageFling;
|
||||
private final SmoothScaler mSmoothScaler;
|
||||
private final OverScroller mOverScroller;
|
||||
private final Rect mTempRect = new Rect();
|
||||
private GalleryView.Adapter mAdapter;
|
||||
private GLProgressView mProgress;
|
||||
@@ -89,7 +86,6 @@ class PagerLayoutManager extends GalleryView.LayoutManager {
|
||||
mSmoothScroller = new SmoothScroller();
|
||||
mPageFling = new PageFling(context);
|
||||
mSmoothScaler = new SmoothScaler();
|
||||
mOverScroller = new OverScroller();
|
||||
}
|
||||
|
||||
public void setInterval(int interval) {
|
||||
@@ -120,12 +116,10 @@ class PagerLayoutManager extends GalleryView.LayoutManager {
|
||||
private boolean cancelAllAnimations() {
|
||||
boolean running = mSmoothScroller.isRunning() ||
|
||||
mPageFling.isRunning() ||
|
||||
mSmoothScaler.isRunning() ||
|
||||
mOverScroller.isRunning();
|
||||
mSmoothScaler.isRunning();
|
||||
mSmoothScroller.cancel();
|
||||
mPageFling.cancel();
|
||||
mSmoothScaler.cancel();
|
||||
mOverScroller.cancel();
|
||||
return running;
|
||||
}
|
||||
|
||||
@@ -417,8 +411,6 @@ class PagerLayoutManager extends GalleryView.LayoutManager {
|
||||
|
||||
@Override
|
||||
public void onUp() {
|
||||
mGalleryView.getEdgeView().onRelease();
|
||||
|
||||
if (mCurrent == null) {
|
||||
return;
|
||||
}
|
||||
@@ -580,39 +572,6 @@ class PagerLayoutManager extends GalleryView.LayoutManager {
|
||||
return remain;
|
||||
}
|
||||
|
||||
public void overScrollEdge(int dx, int dy, float x, float y) {
|
||||
GLEdgeView edgeView = mGalleryView.getEdgeView();
|
||||
|
||||
mDeltaX += dx;
|
||||
mDeltaY += dy;
|
||||
|
||||
if (mDeltaX < 0) {
|
||||
edgeView.onPull(-mDeltaX, y, GLEdgeView.LEFT);
|
||||
if (!edgeView.isFinished(GLEdgeView.RIGHT)) {
|
||||
edgeView.onRelease(GLEdgeView.RIGHT);
|
||||
}
|
||||
} else if (mDeltaX > 0) {
|
||||
edgeView.onPull(mDeltaX, y, GLEdgeView.RIGHT);
|
||||
if (!edgeView.isFinished(GLEdgeView.LEFT)) {
|
||||
edgeView.onRelease(GLEdgeView.LEFT);
|
||||
}
|
||||
}
|
||||
|
||||
if (mCurrent.getImageView().canFlingVertically()) {
|
||||
if (mDeltaY < 0) {
|
||||
edgeView.onPull(-mDeltaY, x, GLEdgeView.TOP);
|
||||
if (!edgeView.isFinished(GLEdgeView.BOTTOM)) {
|
||||
edgeView.onRelease(GLEdgeView.BOTTOM);
|
||||
}
|
||||
} else if (mDeltaY > 0) {
|
||||
edgeView.onPull(mDeltaY, x, GLEdgeView.BOTTOM);
|
||||
if (!edgeView.isFinished(GLEdgeView.TOP)) {
|
||||
edgeView.onRelease(GLEdgeView.TOP);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void scrollInternal(float dx, float dy, float x, float y) {
|
||||
if (mCurrent == null) {
|
||||
return;
|
||||
@@ -640,7 +599,6 @@ class PagerLayoutManager extends GalleryView.LayoutManager {
|
||||
(getLeftPage() == null && mOffset == 0 && remainX < 0) ||
|
||||
(getRightPage() == null && mOffset == 0 && remainX > 0)) {
|
||||
// On edge
|
||||
overScrollEdge(remainX, remainY, x, y);
|
||||
remainX = 0;
|
||||
remainY = 0;
|
||||
} else if (mCanScrollBetweenPages) {
|
||||
@@ -699,7 +657,6 @@ class PagerLayoutManager extends GalleryView.LayoutManager {
|
||||
boolean invalidate = mSmoothScroller.calculate(time);
|
||||
invalidate |= mPageFling.calculate(time);
|
||||
invalidate |= mSmoothScaler.calculate(time);
|
||||
invalidate |= mOverScroller.calculate(time);
|
||||
return invalidate;
|
||||
}
|
||||
|
||||
@@ -726,15 +683,11 @@ class PagerLayoutManager extends GalleryView.LayoutManager {
|
||||
}
|
||||
|
||||
if (mMode == MODE_LEFT_TO_RIGHT) {
|
||||
if (mIndex == 0) {
|
||||
mOverScroller.overScroll(GLEdgeView.LEFT);
|
||||
} else {
|
||||
if (mIndex != 0) {
|
||||
setCurrentIndex(mIndex - 1);
|
||||
}
|
||||
} else {
|
||||
if (mIndex >= size - 1) {
|
||||
mOverScroller.overScroll(GLEdgeView.LEFT);
|
||||
} else {
|
||||
if (mIndex < size - 1) {
|
||||
setCurrentIndex(mIndex + 1);
|
||||
}
|
||||
}
|
||||
@@ -748,15 +701,11 @@ class PagerLayoutManager extends GalleryView.LayoutManager {
|
||||
}
|
||||
|
||||
if (mMode == MODE_LEFT_TO_RIGHT) {
|
||||
if (mIndex >= size - 1) {
|
||||
mOverScroller.overScroll(GLEdgeView.RIGHT);
|
||||
} else {
|
||||
if (mIndex < size - 1) {
|
||||
setCurrentIndex(mIndex + 1);
|
||||
}
|
||||
} else {
|
||||
if (mIndex == 0) {
|
||||
mOverScroller.overScroll(GLEdgeView.RIGHT);
|
||||
} else {
|
||||
if (mIndex != 0) {
|
||||
setCurrentIndex(mIndex - 1);
|
||||
}
|
||||
}
|
||||
@@ -973,34 +922,6 @@ class PagerLayoutManager extends GalleryView.LayoutManager {
|
||||
mLastX = x;
|
||||
mLastY = y;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onFinish() {
|
||||
if (mCurrent == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
GLEdgeView edgeView = mGalleryView.getEdgeView();
|
||||
ImageView imageView = mCurrent.getImageView();
|
||||
if (imageView.canFlingHorizontally()) {
|
||||
if (mVelocityX > 0 && getLeftPage() == null && imageView.getMaxDx() == 0 &&
|
||||
edgeView.isFinished(GLEdgeView.LEFT)) {
|
||||
edgeView.onAbsorb(mVelocityX, GLEdgeView.LEFT);
|
||||
} else if (mVelocityX < 0 && getRightPage() == null && imageView.getMinDx() == 0 &&
|
||||
edgeView.isFinished(GLEdgeView.RIGHT)) {
|
||||
edgeView.onAbsorb(-mVelocityX, GLEdgeView.RIGHT);
|
||||
}
|
||||
}
|
||||
if (imageView.canFlingVertically()) {
|
||||
if (mVelocityY > 0 && imageView.getMaxDy() == 0 &&
|
||||
edgeView.isFinished(GLEdgeView.TOP)) {
|
||||
edgeView.onAbsorb(mVelocityY, GLEdgeView.TOP);
|
||||
} else if (mVelocityY < 0 && imageView.getMinDy() == 0 &&
|
||||
edgeView.isFinished(GLEdgeView.BOTTOM)) {
|
||||
edgeView.onAbsorb(-mVelocityY, GLEdgeView.BOTTOM);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class SmoothScaler extends Animation {
|
||||
@@ -1039,47 +960,4 @@ class PagerLayoutManager extends GalleryView.LayoutManager {
|
||||
mScaleValue = scale;
|
||||
}
|
||||
}
|
||||
|
||||
private class OverScroller extends FloatAnimation {
|
||||
|
||||
private int mDirection;
|
||||
private int mPosition;
|
||||
|
||||
public OverScroller() {
|
||||
setDuration(300L);
|
||||
}
|
||||
|
||||
public void overScroll(int direction) {
|
||||
mDirection = direction;
|
||||
int range;
|
||||
switch (mDirection) {
|
||||
case GLEdgeView.LEFT:
|
||||
case GLEdgeView.RIGHT:
|
||||
range = mGalleryView.getWidth() / 7;
|
||||
mPosition = mGalleryView.getHeight() / 2;
|
||||
break;
|
||||
case GLEdgeView.TOP:
|
||||
case GLEdgeView.BOTTOM:
|
||||
range = mGalleryView.getHeight() / 7;
|
||||
mPosition = mGalleryView.getWidth() / 2;
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
setRange(0, range);
|
||||
start();
|
||||
mGalleryView.invalidate();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onCalculate(float progress) {
|
||||
super.onCalculate(progress);
|
||||
mGalleryView.getEdgeView().onPull(get(), mPosition, mDirection);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onFinish() {
|
||||
mGalleryView.getEdgeView().onRelease(mDirection);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -23,9 +23,7 @@ import android.util.Log;
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import com.hippo.glview.anim.Animation;
|
||||
import com.hippo.glview.anim.FloatAnimation;
|
||||
import com.hippo.glview.view.GLView;
|
||||
import com.hippo.glview.widget.GLEdgeView;
|
||||
import com.hippo.glview.widget.GLProgressView;
|
||||
import com.hippo.glview.widget.GLTextureView;
|
||||
import com.hippo.yorozuya.AnimationUtils;
|
||||
@@ -51,7 +49,6 @@ class ScrollLayoutManager extends GalleryView.LayoutManager {
|
||||
private final LinkedList<GalleryPageView> mTempPages = new LinkedList<>();
|
||||
private final PageFling mPageFling;
|
||||
private final SmoothScaler mSmoothScaler;
|
||||
private final OverScroller mOverScroller;
|
||||
private GalleryView.Adapter mAdapter;
|
||||
private GLProgressView mProgress;
|
||||
private String mErrorStr;
|
||||
@@ -80,7 +77,6 @@ class ScrollLayoutManager extends GalleryView.LayoutManager {
|
||||
mInterval = interval;
|
||||
mPageFling = new PageFling(context);
|
||||
mSmoothScaler = new SmoothScaler();
|
||||
mOverScroller = new OverScroller();
|
||||
}
|
||||
|
||||
public void setInterval(int interval) {
|
||||
@@ -117,11 +113,9 @@ class ScrollLayoutManager extends GalleryView.LayoutManager {
|
||||
// Return true for animations are running
|
||||
private boolean cancelAllAnimations() {
|
||||
boolean running = mPageFling.isRunning() ||
|
||||
mSmoothScaler.isRunning() ||
|
||||
mOverScroller.isRunning();
|
||||
mSmoothScaler.isRunning();
|
||||
mPageFling.cancel();
|
||||
mSmoothScaler.cancel();
|
||||
mOverScroller.cancel();
|
||||
return running;
|
||||
}
|
||||
|
||||
@@ -536,7 +530,6 @@ class ScrollLayoutManager extends GalleryView.LayoutManager {
|
||||
@Override
|
||||
public void onUp() {
|
||||
mScrollUp = false;
|
||||
mGalleryView.getEdgeView().onRelease();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -561,37 +554,6 @@ class ScrollLayoutManager extends GalleryView.LayoutManager {
|
||||
|
||||
}
|
||||
|
||||
public void overScrollEdge(int dx, int dy, float x, float y) {
|
||||
GLEdgeView edgeView = mGalleryView.getEdgeView();
|
||||
|
||||
mDeltaX += dx;
|
||||
mDeltaY += dy;
|
||||
|
||||
if (mDeltaX < 0) {
|
||||
edgeView.onPull(-mDeltaX, y, GLEdgeView.LEFT);
|
||||
if (!edgeView.isFinished(GLEdgeView.RIGHT)) {
|
||||
edgeView.onRelease(GLEdgeView.RIGHT);
|
||||
}
|
||||
} else if (mDeltaX > 0) {
|
||||
edgeView.onPull(mDeltaX, y, GLEdgeView.RIGHT);
|
||||
if (!edgeView.isFinished(GLEdgeView.LEFT)) {
|
||||
edgeView.onRelease(GLEdgeView.LEFT);
|
||||
}
|
||||
}
|
||||
|
||||
if (mDeltaY < 0) {
|
||||
edgeView.onPull(-mDeltaY, x, GLEdgeView.TOP);
|
||||
if (!edgeView.isFinished(GLEdgeView.BOTTOM)) {
|
||||
edgeView.onRelease(GLEdgeView.BOTTOM);
|
||||
}
|
||||
} else if (mDeltaY > 0) {
|
||||
edgeView.onPull(mDeltaY, x, GLEdgeView.BOTTOM);
|
||||
if (!edgeView.isFinished(GLEdgeView.TOP)) {
|
||||
edgeView.onRelease(GLEdgeView.TOP);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void getBottomState() {
|
||||
List<GalleryPageView> pages = mPages;
|
||||
int bottom = mOffsetY;
|
||||
@@ -673,9 +635,6 @@ class ScrollLayoutManager extends GalleryView.LayoutManager {
|
||||
mOffsetY = limit;
|
||||
requestFill = true;
|
||||
}
|
||||
if (!fling) {
|
||||
overScrollEdge(0, remainY + limit - mOffsetY, x, y);
|
||||
}
|
||||
remainY = 0;
|
||||
result = true;
|
||||
}
|
||||
@@ -716,9 +675,6 @@ class ScrollLayoutManager extends GalleryView.LayoutManager {
|
||||
mOffsetY -= bottom - limit;
|
||||
requestFill = true;
|
||||
}
|
||||
if (!fling) {
|
||||
overScrollEdge(0, remainY + limit - bottom, x, y);
|
||||
}
|
||||
remainY = 0;
|
||||
result = true;
|
||||
}
|
||||
@@ -841,7 +797,6 @@ class ScrollLayoutManager extends GalleryView.LayoutManager {
|
||||
public boolean onUpdateAnimation(long time) {
|
||||
boolean invalidate = mPageFling.calculate(time);
|
||||
invalidate |= mSmoothScaler.calculate(time);
|
||||
invalidate |= mOverScroller.calculate(time);
|
||||
return invalidate;
|
||||
}
|
||||
|
||||
@@ -872,7 +827,6 @@ class ScrollLayoutManager extends GalleryView.LayoutManager {
|
||||
///////
|
||||
GalleryView galleryView = mGalleryView;
|
||||
if (mIndex == 0 && mOffsetY >= 0) {
|
||||
mOverScroller.overScroll(GLEdgeView.TOP);
|
||||
} else {
|
||||
// Cancel all animations
|
||||
cancelAllAnimations();
|
||||
@@ -926,9 +880,7 @@ class ScrollLayoutManager extends GalleryView.LayoutManager {
|
||||
getBottomState();
|
||||
int bottom = mBottomStateBottom;
|
||||
boolean hasNext = mBottomStateHasNext;
|
||||
if (!hasNext && bottom <= galleryView.getHeight()) {
|
||||
mOverScroller.overScroll(GLEdgeView.BOTTOM);
|
||||
} else {
|
||||
if (hasNext || bottom > galleryView.getHeight()) {
|
||||
// Cancel all animations
|
||||
cancelAllAnimations();
|
||||
|
||||
@@ -1141,17 +1093,6 @@ class ScrollLayoutManager extends GalleryView.LayoutManager {
|
||||
int bottom = mBottomStateBottom;
|
||||
boolean hasNext = mBottomStateHasNext;
|
||||
boolean bottomEdge = !hasNext && bottom <= mGalleryView.getHeight();
|
||||
|
||||
if (topEdge && bottomEdge) {
|
||||
return;
|
||||
}
|
||||
|
||||
GLEdgeView edgeView = mGalleryView.getEdgeView();
|
||||
if (topEdge && edgeView.isFinished(GLEdgeView.TOP)) {
|
||||
edgeView.onAbsorb(mVelocityY, GLEdgeView.TOP);
|
||||
} else if (bottomEdge && edgeView.isFinished(GLEdgeView.BOTTOM)) {
|
||||
edgeView.onAbsorb(-mVelocityY, GLEdgeView.BOTTOM);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1190,47 +1131,4 @@ class ScrollLayoutManager extends GalleryView.LayoutManager {
|
||||
mLastScale = scale;
|
||||
}
|
||||
}
|
||||
|
||||
private class OverScroller extends FloatAnimation {
|
||||
|
||||
private int mDirection;
|
||||
private int mPosition;
|
||||
|
||||
public OverScroller() {
|
||||
setDuration(300L);
|
||||
}
|
||||
|
||||
public void overScroll(int direction) {
|
||||
mDirection = direction;
|
||||
int range;
|
||||
switch (mDirection) {
|
||||
case GLEdgeView.LEFT:
|
||||
case GLEdgeView.RIGHT:
|
||||
range = mGalleryView.getWidth() / 7;
|
||||
mPosition = mGalleryView.getHeight() / 2;
|
||||
break;
|
||||
case GLEdgeView.TOP:
|
||||
case GLEdgeView.BOTTOM:
|
||||
range = mGalleryView.getHeight() / 7;
|
||||
mPosition = mGalleryView.getWidth() / 2;
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
setRange(0, range);
|
||||
start();
|
||||
mGalleryView.invalidate();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onCalculate(float progress) {
|
||||
super.onCalculate(progress);
|
||||
mGalleryView.getEdgeView().onPull(get(), mPosition, mDirection);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onFinish() {
|
||||
mGalleryView.getEdgeView().onRelease(mDirection);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,360 +0,0 @@
|
||||
/*
|
||||
* Copyright 2016 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
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.hippo.glview.widget;
|
||||
|
||||
import android.graphics.Rect;
|
||||
import android.view.animation.AnimationUtils;
|
||||
import android.view.animation.DecelerateInterpolator;
|
||||
import android.view.animation.Interpolator;
|
||||
|
||||
import com.hippo.glview.glrenderer.GLCanvas;
|
||||
|
||||
/**
|
||||
* Material design edge effect
|
||||
*/
|
||||
public class GLEdgeEffect {
|
||||
|
||||
// Time it will take the effect to fully recede in ms
|
||||
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 = 2000;
|
||||
|
||||
private static final float MAX_ALPHA = 0.5f;
|
||||
|
||||
private static final float MAX_GLOW_SCALE = 2.f;
|
||||
|
||||
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 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 static final int STATE_IDLE = 0;
|
||||
private static final int STATE_PULL = 1;
|
||||
private static final int STATE_ABSORB = 2;
|
||||
private static final int STATE_RECEDE = 3;
|
||||
private static final int STATE_PULL_DECAY = 4;
|
||||
private static final float PULL_DISTANCE_ALPHA_GLOW_FACTOR = 0.8f;
|
||||
private static final int VELOCITY_GLOW_FACTOR = 6;
|
||||
private final Interpolator mInterpolator;
|
||||
private final Rect mBounds = new Rect();
|
||||
private float mGlowAlpha;
|
||||
private float mGlowScaleY;
|
||||
private float mGlowAlphaStart;
|
||||
private float mGlowAlphaFinish;
|
||||
private float mGlowScaleYStart;
|
||||
private float mGlowScaleYFinish;
|
||||
private long mStartTime;
|
||||
private float mDuration;
|
||||
private int mState = STATE_IDLE;
|
||||
private float mPullDistance;
|
||||
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.
|
||||
*/
|
||||
public GLEdgeEffect(int color) {
|
||||
mColor = color;
|
||||
mInterpolator = new DecelerateInterpolator();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the size of this edge effect in pixels.
|
||||
*
|
||||
* @param width Effect width in pixels
|
||||
* @param height Effect height in pixels
|
||||
*/
|
||||
public void setSize(int width, int 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));
|
||||
}
|
||||
|
||||
/**
|
||||
* Reports if this EdgeEffect's animation is finished. If this method returns false
|
||||
* after a call to {@link #draw(GLCanvas)} the host widget should schedule another
|
||||
* drawing pass to continue the animation.
|
||||
*
|
||||
* @return true if animation is finished, false if drawing should continue on the next frame.
|
||||
*/
|
||||
public boolean isFinished() {
|
||||
return mState == STATE_IDLE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Immediately finish the current animation.
|
||||
* After this call {@link #isFinished()} will return true.
|
||||
*/
|
||||
public void finish() {
|
||||
mState = STATE_IDLE;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
* <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 = Math.max(PULL_GLOW_BEGIN, mGlowScaleY);
|
||||
}
|
||||
mState = STATE_PULL;
|
||||
|
||||
mStartTime = now;
|
||||
mDuration = PULL_TIME;
|
||||
|
||||
mPullDistance += deltaDistance;
|
||||
|
||||
final float absdd = Math.abs(deltaDistance);
|
||||
mGlowAlpha = mGlowAlphaStart = Math.min(MAX_ALPHA,
|
||||
mGlowAlpha + (absdd * PULL_DISTANCE_ALPHA_GLOW_FACTOR));
|
||||
|
||||
if (mPullDistance == 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;
|
||||
}
|
||||
|
||||
mGlowAlphaFinish = mGlowAlpha;
|
||||
mGlowScaleYFinish = mGlowScaleY;
|
||||
}
|
||||
|
||||
/**
|
||||
* Call when the object is released after being pulled.
|
||||
* This will begin the "decay" phase of the effect. After calling this method
|
||||
* the host view should {@link android.view.View#invalidate()} and thereby
|
||||
* draw the results accordingly.
|
||||
*/
|
||||
public void onRelease() {
|
||||
mPullDistance = 0;
|
||||
|
||||
if (mState != STATE_PULL && mState != STATE_PULL_DECAY) {
|
||||
return;
|
||||
}
|
||||
|
||||
mState = STATE_RECEDE;
|
||||
mGlowAlphaStart = mGlowAlpha;
|
||||
mGlowScaleYStart = mGlowScaleY;
|
||||
|
||||
mGlowAlphaFinish = 0.f;
|
||||
mGlowScaleYFinish = 0.f;
|
||||
|
||||
mStartTime = AnimationUtils.currentAnimationTimeMillis();
|
||||
mDuration = RECEDE_TIME;
|
||||
}
|
||||
|
||||
/**
|
||||
* Call when the effect absorbs an impact at the given velocity.
|
||||
* Used when a fling reaches the scroll boundary.
|
||||
*
|
||||
* <p>When using a {@link android.widget.Scroller} or {@link android.widget.OverScroller},
|
||||
* the method <code>getCurrVelocity</code> will provide a reasonable approximation
|
||||
* to use here.</p>
|
||||
*
|
||||
* @param velocity Velocity at impact in pixels per second.
|
||||
*/
|
||||
public void onAbsorb(int velocity) {
|
||||
mState = STATE_ABSORB;
|
||||
velocity = Math.min(Math.max(MIN_VELOCITY, Math.abs(velocity)), MAX_VELOCITY);
|
||||
|
||||
mStartTime = AnimationUtils.currentAnimationTimeMillis();
|
||||
mDuration = 0.15f + (velocity * 0.02f);
|
||||
|
||||
// The glow depends more on the velocity, and therefore starts out
|
||||
// nearly invisible.
|
||||
mGlowAlphaStart = 0.3f;
|
||||
mGlowScaleYStart = Math.max(mGlowScaleY, 0.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) / 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the color of this edge effect in argb.
|
||||
*
|
||||
* @return The color of this edge effect in argb
|
||||
*/
|
||||
public int getColor() {
|
||||
return mColor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the color of this edge effect in argb.
|
||||
*
|
||||
* @param color Color in argb
|
||||
*/
|
||||
public void setColor(int color) {
|
||||
mColor = color;
|
||||
}
|
||||
|
||||
/**
|
||||
* Draw into the provided canvas. Assumes that the canvas has been rotated
|
||||
* accordingly and the size has been set. The effect will be drawn the full
|
||||
* width of X=0 to X=width, beginning from Y=0 and extending to some factor <
|
||||
* 1.f of height.
|
||||
*
|
||||
* @param canvas Canvas to draw into
|
||||
* @return true if drawing should continue beyond this frame to continue the
|
||||
* animation
|
||||
*/
|
||||
public boolean draw(GLCanvas canvas) {
|
||||
update();
|
||||
|
||||
canvas.save();
|
||||
|
||||
final float centerX = mBounds.centerX();
|
||||
final float centerY = mBounds.height() - mRadius;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
return mState != STATE_IDLE || oneLastFrame;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 = AnimationUtils.currentAnimationTimeMillis();
|
||||
final float t = Math.min((time - mStartTime) / mDuration, 1.f);
|
||||
|
||||
final float interp = mInterpolator.getInterpolation(t);
|
||||
|
||||
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 = AnimationUtils.currentAnimationTimeMillis();
|
||||
mDuration = RECEDE_TIME;
|
||||
|
||||
mGlowAlphaStart = mGlowAlpha;
|
||||
mGlowScaleYStart = mGlowScaleY;
|
||||
|
||||
// After absorb, the glow should fade to nothing.
|
||||
mGlowAlphaFinish = 0.f;
|
||||
mGlowScaleYFinish = 0.f;
|
||||
break;
|
||||
case STATE_PULL:
|
||||
mState = STATE_PULL_DECAY;
|
||||
mStartTime = AnimationUtils.currentAnimationTimeMillis();
|
||||
mDuration = PULL_DECAY_TIME;
|
||||
|
||||
mGlowAlphaStart = mGlowAlpha;
|
||||
mGlowScaleYStart = mGlowScaleY;
|
||||
|
||||
// After pull, the glow should fade to nothing.
|
||||
mGlowAlphaFinish = 0.f;
|
||||
mGlowScaleYFinish = 0.f;
|
||||
break;
|
||||
case STATE_PULL_DECAY:
|
||||
mState = STATE_RECEDE;
|
||||
break;
|
||||
case STATE_RECEDE:
|
||||
mState = STATE_IDLE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,162 +0,0 @@
|
||||
/*
|
||||
* Copyright 2016 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
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.hippo.glview.widget;
|
||||
|
||||
import android.opengl.Matrix;
|
||||
|
||||
import androidx.annotation.IntDef;
|
||||
|
||||
import com.hippo.glview.glrenderer.GLCanvas;
|
||||
import com.hippo.glview.view.GLView;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
|
||||
public final class GLEdgeView extends GLView {
|
||||
|
||||
public static final int TOP = 0;
|
||||
public static final int LEFT = 1;
|
||||
public static final int BOTTOM = 2;
|
||||
public static final int RIGHT = 3;
|
||||
// Each edge effect has a transform matrix, and each matrix has 16 elements.
|
||||
// We put all the elements in one array. These constants specify the
|
||||
// starting index of each matrix.
|
||||
private static final int TOP_M = TOP * 16;
|
||||
private static final int LEFT_M = LEFT * 16;
|
||||
private static final int BOTTOM_M = BOTTOM * 16;
|
||||
private static final int RIGHT_M = RIGHT * 16;
|
||||
private final GLEdgeEffect[] mEffect = new GLEdgeEffect[4];
|
||||
private final float[] mMatrix = new float[4 * 16];
|
||||
|
||||
public GLEdgeView(int color) {
|
||||
for (int i = 0; i < 4; i++) {
|
||||
mEffect[i] = new GLEdgeEffect(color);
|
||||
}
|
||||
}
|
||||
|
||||
public void setColor(int color) {
|
||||
for (int i = 0; i < 4; i++) {
|
||||
mEffect[i].setColor(color);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onLayout(
|
||||
boolean changeSize, int left, int top, int right, int bottom) {
|
||||
if (!changeSize) return;
|
||||
|
||||
int w = right - left;
|
||||
int h = bottom - top;
|
||||
for (int i = 0; i < 4; i++) {
|
||||
if ((i & 1) == 0) { // top or bottom
|
||||
mEffect[i].setSize(w, h);
|
||||
} else { // left or right
|
||||
mEffect[i].setSize(h, w);
|
||||
}
|
||||
}
|
||||
|
||||
// Set up transforms for the four edges. Without transforms an
|
||||
// EdgeEffect draws the TOP edge from (0, 0) to (w, Y * h) where Y
|
||||
// is some factor < 1. For other edges we need to move, rotate, and
|
||||
// flip the effects into proper places.
|
||||
Matrix.setIdentityM(mMatrix, TOP_M);
|
||||
Matrix.setIdentityM(mMatrix, LEFT_M);
|
||||
Matrix.setIdentityM(mMatrix, BOTTOM_M);
|
||||
Matrix.setIdentityM(mMatrix, RIGHT_M);
|
||||
|
||||
Matrix.rotateM(mMatrix, LEFT_M, 90, 0, 0, 1);
|
||||
Matrix.scaleM(mMatrix, LEFT_M, 1, -1, 1);
|
||||
|
||||
Matrix.translateM(mMatrix, BOTTOM_M, 0, h, 0);
|
||||
Matrix.scaleM(mMatrix, BOTTOM_M, 1, -1, 1);
|
||||
|
||||
Matrix.translateM(mMatrix, RIGHT_M, w, 0, 0);
|
||||
Matrix.rotateM(mMatrix, RIGHT_M, 90, 0, 0, 1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void render(GLCanvas canvas) {
|
||||
boolean more = false;
|
||||
for (int i = 0; i < 4; i++) {
|
||||
canvas.save(GLCanvas.SAVE_FLAG_MATRIX);
|
||||
canvas.multiplyMatrix(mMatrix, i * 16);
|
||||
more |= mEffect[i].draw(canvas);
|
||||
canvas.restore();
|
||||
}
|
||||
if (more) {
|
||||
invalidate();
|
||||
}
|
||||
}
|
||||
|
||||
// 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(float offset, @Direction int direction) {
|
||||
int fullLength = ((direction & 1) == 0) ? getWidth() : getHeight();
|
||||
mEffect[direction].onPull(offset / fullLength);
|
||||
if (!mEffect[direction].isFinished()) {
|
||||
invalidate();
|
||||
}
|
||||
}
|
||||
|
||||
public void onPull(float offset, float position, @Direction int direction) {
|
||||
int fullLength = ((direction & 1) == 0) ? getHeight() : getWidth();
|
||||
int fullPosition = ((direction & 1) == 0) ? getWidth() : getHeight();
|
||||
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;
|
||||
for (int i = 0; i < 4; i++) {
|
||||
mEffect[i].onRelease();
|
||||
more |= !mEffect[i].isFinished();
|
||||
}
|
||||
if (more) {
|
||||
invalidate();
|
||||
}
|
||||
}
|
||||
|
||||
public void onRelease(@Direction int direction) {
|
||||
GLEdgeEffect edgeEffect = mEffect[direction];
|
||||
edgeEffect.onRelease();
|
||||
if (!edgeEffect.isFinished()) {
|
||||
invalidate();
|
||||
}
|
||||
}
|
||||
|
||||
// Call when the effect absorbs an impact at the given velocity.
|
||||
// Used when a fling reaches the scroll boundary. velocity is in pixels
|
||||
// per second. direction is one of {TOP, LEFT, BOTTOM, RIGHT}.
|
||||
public void onAbsorb(int velocity, int direction) {
|
||||
mEffect[direction].onAbsorb(velocity);
|
||||
if (!mEffect[direction].isFinished()) {
|
||||
invalidate();
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isFinished(int direction) {
|
||||
return mEffect[direction].isFinished();
|
||||
}
|
||||
|
||||
@IntDef({TOP, LEFT, BOTTOM, RIGHT})
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
private @interface Direction {
|
||||
}
|
||||
}
|
||||
@@ -17,7 +17,6 @@
|
||||
<resources>
|
||||
|
||||
<declare-styleable name="Theme">
|
||||
<attr name="colorEdgeEffect" format="color" />
|
||||
<attr name="dividerColor" format="color" />
|
||||
<attr name="drawableColorSecondary" format="color" />
|
||||
<attr name="drawableColorThemePrimary" format="color" />
|
||||
|
||||
@@ -21,7 +21,6 @@
|
||||
<!-- ========== -->
|
||||
|
||||
<style name="Base.AppTheme" parent="Theme.Material3.DynamicColors.DayNight">
|
||||
<item name="colorEdgeEffect">@color/grey_500</item>
|
||||
<item name="dividerColor">@color/divider</item>
|
||||
<item name="drawableColorSecondary">?attr/colorOnSurface</item>
|
||||
<item name="drawableColorThemePrimary">?attr/colorPrimary</item>
|
||||
|
||||
Reference in new issue
Block a user