Improve GalleryView
This commit is contained in:
1 parent
a585c7cd20
commit
293ada12c6
16 files changed
+557
-656
No files matched your search
@@ -25,13 +25,20 @@ import android.view.MotionEvent;
|
||||
import com.hippo.ehviewer.R;
|
||||
import com.hippo.ehviewer.ui.gl.GalleryPageView;
|
||||
import com.hippo.ehviewer.ui.gl.GalleryView;
|
||||
import com.hippo.gl.glrenderer.ImageTexture;
|
||||
import com.hippo.gl.view.GLRootView;
|
||||
import com.hippo.image.Image;
|
||||
import com.hippo.util.Dpad;
|
||||
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
|
||||
public class GalleryActivity extends AppCompatActivity {
|
||||
|
||||
private GalleryView mGalleryView;
|
||||
|
||||
private ImageTexture.Uploader mUploader;
|
||||
|
||||
@Override
|
||||
protected void onCreate(@Nullable Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
@@ -40,12 +47,14 @@ public class GalleryActivity extends AppCompatActivity {
|
||||
GLRootView glRootView = (GLRootView) findViewById(R.id.gl_root_view);
|
||||
mGalleryView = new GalleryView(this, new InvalidPageIterator(), null);
|
||||
glRootView.setContentPane(mGalleryView);
|
||||
mUploader = new ImageTexture.Uploader(glRootView);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDestroy() {
|
||||
super.onDestroy();
|
||||
mGalleryView = null;
|
||||
mUploader = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -145,51 +154,73 @@ public class GalleryActivity extends AppCompatActivity {
|
||||
}
|
||||
|
||||
|
||||
private static final int MAX_SIZE = 10;
|
||||
|
||||
private class InvalidPageIterator implements GalleryView.PageIterator {
|
||||
|
||||
private int mIndex = 0;
|
||||
private int mBackup = mIndex;
|
||||
|
||||
public ImageTexture mImageTexture;
|
||||
|
||||
public InvalidPageIterator() {
|
||||
try {
|
||||
mImageTexture = new ImageTexture(Image.decode(new FileInputStream("/sdcard/1.jpg"), false));
|
||||
} catch (FileNotFoundException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mark() {
|
||||
|
||||
mBackup = mIndex;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reset() {
|
||||
|
||||
mIndex = mBackup;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
return false;
|
||||
return mIndex < MAX_SIZE - 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasPrevious() {
|
||||
return false;
|
||||
return mIndex > 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isValid() {
|
||||
return false;
|
||||
return mIndex >= 0 && mIndex < MAX_SIZE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void next() {
|
||||
|
||||
if (mIndex >= MAX_SIZE - 1) {
|
||||
throw new IndexOutOfBoundsException();
|
||||
}
|
||||
mIndex++;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void previous() {
|
||||
|
||||
if (mIndex <= 0) {
|
||||
throw new IndexOutOfBoundsException();
|
||||
}
|
||||
mIndex--;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void bind(GalleryPageView view) {
|
||||
|
||||
//view.showImage();
|
||||
view.getImageView().setTexture(mImageTexture);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unbind(GalleryPageView view) {
|
||||
|
||||
view.getImageView().setTexture(null);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@ import android.view.animation.Interpolator;
|
||||
|
||||
import com.hippo.gl.anim.Animation;
|
||||
|
||||
class Fling extends Animation {
|
||||
public abstract class Fling extends Animation {
|
||||
|
||||
private static final float DECELERATION_RATE = (float) (Math.log(0.78) / Math.log(0.9));
|
||||
private static final float INFLEXION = 0.35f; // Tension lines cross at (INFLEXION, 1)
|
||||
@@ -39,13 +39,6 @@ class Fling extends Animation {
|
||||
|
||||
private float mPhysicalCoeff;
|
||||
|
||||
//private GalleryPageView mPage;
|
||||
private int mDx;
|
||||
private int mDy;
|
||||
private int mLastX;
|
||||
private int mLastY;
|
||||
private int[] mTemp = new int[2];
|
||||
|
||||
static {
|
||||
float x_min = 0.0f;
|
||||
float y_min = 0.0f;
|
||||
@@ -103,6 +96,7 @@ class Fling extends Animation {
|
||||
* 39.37f // inch/meter
|
||||
* ppi
|
||||
* 0.84f; // look and feel tuning
|
||||
setInterpolator(FLING_INTERPOLATOR);
|
||||
}
|
||||
|
||||
private double getSplineDeceleration(int velocity) {
|
||||
@@ -110,13 +104,13 @@ class Fling extends Animation {
|
||||
}
|
||||
|
||||
/* Returns the duration, expressed in milliseconds */
|
||||
private int getSplineFlingDuration(int velocity) {
|
||||
protected int getSplineFlingDuration(int velocity) {
|
||||
final double l = getSplineDeceleration(velocity);
|
||||
final double decelMinusOne = DECELERATION_RATE - 1.0;
|
||||
return (int) (1000.0 * Math.exp(l / decelMinusOne));
|
||||
}
|
||||
|
||||
private double getSplineFlingDistance(int velocity) {
|
||||
protected double getSplineFlingDistance(int velocity) {
|
||||
final double l = getSplineDeceleration(velocity);
|
||||
final double decelMinusOne = DECELERATION_RATE - 1.0;
|
||||
return FLING_FRICTION * mPhysicalCoeff * Math.exp(DECELERATION_RATE / decelMinusOne * l);
|
||||
@@ -126,7 +120,7 @@ class Fling extends Animation {
|
||||
* Modifies mDuration to the duration it takes to get from start to newFinal using the
|
||||
* spline interpolation. The previous duration was needed to get to oldFinal.
|
||||
**/
|
||||
private int adjustDuration(int start, int oldFinal, int newFinal, int duration) {
|
||||
protected int adjustDuration(int start, int oldFinal, int newFinal, int duration) {
|
||||
final int oldDistance = oldFinal - start;
|
||||
final int newDistance = newFinal - start;
|
||||
final float x = Math.abs((float) newDistance / oldDistance);
|
||||
@@ -141,49 +135,4 @@ class Fling extends Animation {
|
||||
}
|
||||
return duration;
|
||||
}
|
||||
|
||||
public void startFling(GalleryPageView page, int velocityX, int minX, int maxX,
|
||||
int velocityY, int minY, int maxY) {
|
||||
//mPage = page;
|
||||
mDx = (int) (getSplineFlingDistance(velocityX) * Math.signum(velocityX));
|
||||
mDy = (int) (getSplineFlingDistance(velocityY) * Math.signum(velocityY));
|
||||
mLastX = 0;
|
||||
mLastY = 0;
|
||||
int durationX = getSplineFlingDuration(velocityX);
|
||||
int durationY = getSplineFlingDuration(velocityY);
|
||||
|
||||
if (mDx < minX) {
|
||||
durationX = adjustDuration(0, mDx, minX, durationX);
|
||||
mDx = minX;
|
||||
}
|
||||
if (mDx > maxX) {
|
||||
durationX = adjustDuration(0, mDx, maxX, durationX);
|
||||
mDx = maxX;
|
||||
}
|
||||
if (mDy < minY) {
|
||||
durationY = adjustDuration(0, mDy, minY, durationY);
|
||||
mDy = minY;
|
||||
}
|
||||
if (mDy > maxY) {
|
||||
durationY = adjustDuration(0, mDy, maxY, durationY);
|
||||
mDy = maxY;
|
||||
}
|
||||
|
||||
setDuration(Math.max(durationX, durationY));
|
||||
start();
|
||||
// TODO invalidate();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onCalculate(float progress) {
|
||||
int x = (int) (mDx * progress);
|
||||
int y = (int) (mDy * progress);
|
||||
int offsetX = x - mLastX;
|
||||
int offsetY = y - mLastY;
|
||||
if (offsetX != 0 || offsetY != 0) {
|
||||
// TODO mPage.scroll(-offsetX, -offsetY, mTemp);
|
||||
}
|
||||
mLastX = x;
|
||||
mLastY = y;
|
||||
}
|
||||
}
|
||||
@@ -29,10 +29,11 @@ import com.hippo.yorozuya.LayoutUtils;
|
||||
|
||||
public class GalleryPageView extends GLFrameLayout {
|
||||
|
||||
public ImageView mImage;
|
||||
public GLTextView mPage;
|
||||
public GLTextureView mError;
|
||||
public GLProgressView mProgress;
|
||||
private ImageView mImage;
|
||||
private GLLinearLayout mInfo;
|
||||
private GLTextView mPage;
|
||||
private GLTextureView mError;
|
||||
private GLProgressView mProgress;
|
||||
|
||||
// TODO
|
||||
private static TextTexture sPageTextTexture;
|
||||
@@ -45,12 +46,12 @@ public class GalleryPageView extends GLFrameLayout {
|
||||
addComponent(mImage, glp);
|
||||
|
||||
// Add other panel
|
||||
GLLinearLayout ll = new GLLinearLayout();
|
||||
ll.setOrientation(GLLinearLayout.VERTICAL);
|
||||
mInfo = new GLLinearLayout();
|
||||
mInfo.setOrientation(GLLinearLayout.VERTICAL);
|
||||
glp = new GravityLayoutParams(LayoutParams.WRAP_CONTENT,
|
||||
LayoutParams.WRAP_CONTENT);
|
||||
glp.gravity = Gravity.CENTER;
|
||||
addComponent(ll, glp);
|
||||
addComponent(mInfo, glp);
|
||||
|
||||
// Add page
|
||||
mPage = new GLTextView();
|
||||
@@ -58,14 +59,14 @@ public class GalleryPageView extends GLFrameLayout {
|
||||
GLLinearLayout.LayoutParams lp = new GLLinearLayout.LayoutParams(LayoutParams.WRAP_CONTENT,
|
||||
LayoutParams.WRAP_CONTENT);
|
||||
lp.gravity = Gravity.CENTER_HORIZONTAL;
|
||||
ll.addComponent(mPage, lp);
|
||||
mInfo.addComponent(mPage, lp);
|
||||
|
||||
// Add error
|
||||
mError = new GLTextureView();
|
||||
lp = new GLLinearLayout.LayoutParams(LayoutParams.WRAP_CONTENT,
|
||||
LayoutParams.WRAP_CONTENT);
|
||||
lp.gravity = Gravity.CENTER_HORIZONTAL;
|
||||
ll.addComponent(mError, lp);
|
||||
mInfo.addComponent(mError, lp);
|
||||
|
||||
// Add progress
|
||||
mProgress = new GLProgressView();
|
||||
@@ -74,7 +75,12 @@ public class GalleryPageView extends GLFrameLayout {
|
||||
lp = new GLLinearLayout.LayoutParams(LayoutParams.WRAP_CONTENT,
|
||||
LayoutParams.WRAP_CONTENT);
|
||||
lp.gravity = Gravity.CENTER_HORIZONTAL;
|
||||
ll.addComponent(mProgress, lp);
|
||||
mInfo.addComponent(mProgress, lp);
|
||||
}
|
||||
|
||||
public void showImage() {
|
||||
//mImage.setVisibility(VISIBLE);
|
||||
//mInfo.setVisibility(INVISIBLE);
|
||||
}
|
||||
|
||||
public ImageView getImageView() {
|
||||
|
||||
@@ -26,6 +26,7 @@ import android.view.animation.Interpolator;
|
||||
import android.view.animation.OvershootInterpolator;
|
||||
|
||||
import com.hippo.ehviewer.R;
|
||||
import com.hippo.gl.annotation.RenderThread;
|
||||
import com.hippo.gl.glrenderer.GLCanvas;
|
||||
import com.hippo.gl.util.GalleryUtils;
|
||||
import com.hippo.gl.view.AnimationTime;
|
||||
@@ -139,7 +140,7 @@ public class GalleryView extends GLView implements GestureRecognizer.Listener {
|
||||
|
||||
int interval = LayoutUtils.dp2pix(context, INTERVAL_IN_DP);
|
||||
int progressSize = LayoutUtils.dp2pix(context, PROGRESS_SIZE_IN_DP);
|
||||
mPagerLayoutManager = new PagerLayoutManager(this, interval, progressSize);
|
||||
mPagerLayoutManager = new PagerLayoutManager(context, this, interval, progressSize);
|
||||
mPagerLayoutManager.onAttach(iterator);
|
||||
mLayoutManager = mPagerLayoutManager;
|
||||
|
||||
@@ -182,12 +183,8 @@ public class GalleryView extends GLView implements GestureRecognizer.Listener {
|
||||
}
|
||||
|
||||
public void requestFill() {
|
||||
if (GalleryUtils.isRenderThread()) {
|
||||
fill();
|
||||
} else {
|
||||
mRequestFill = true;
|
||||
invalidate();
|
||||
}
|
||||
mRequestFill = true;
|
||||
invalidate();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -254,16 +251,9 @@ public class GalleryView extends GLView implements GestureRecognizer.Listener {
|
||||
return onScale(focusX, focusY, 1.0f);
|
||||
}
|
||||
|
||||
private boolean canScale() {
|
||||
if (mLastLayoutMode != LAYOUT_MODE_LEFT_TO_RIGHT && mLastLayoutMode != LAYOUT_MODE_RIGHT_TO_LEFT) {
|
||||
return false;
|
||||
}
|
||||
return !mScroll;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onScale(float focusX, float focusY, float scale) {
|
||||
if (!canScale()) {
|
||||
if (mScroll || !mLayoutManager.canScale()) {
|
||||
return false;
|
||||
}
|
||||
mScale = true;
|
||||
@@ -294,7 +284,7 @@ public class GalleryView extends GLView implements GestureRecognizer.Listener {
|
||||
|
||||
@Override
|
||||
public void onPointerDown(float x, float y) {
|
||||
if (canScale()) {
|
||||
if (!mScroll && mLayoutManager.canScale()) {
|
||||
mScale = true;
|
||||
}
|
||||
}
|
||||
@@ -330,6 +320,7 @@ public class GalleryView extends GLView implements GestureRecognizer.Listener {
|
||||
}
|
||||
}
|
||||
|
||||
@RenderThread
|
||||
private void fill() {
|
||||
// Must be in render thread
|
||||
GalleryUtils.assertInRenderThread();
|
||||
@@ -341,7 +332,7 @@ public class GalleryView extends GLView implements GestureRecognizer.Listener {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRender(GLCanvas canvas) {
|
||||
public void render(GLCanvas canvas) {
|
||||
long time = AnimationTime.get();
|
||||
boolean invalidate = mLayoutManager.onUpdateAnimation(time);
|
||||
if (invalidate) {
|
||||
@@ -354,7 +345,8 @@ public class GalleryView extends GLView implements GestureRecognizer.Listener {
|
||||
fill();
|
||||
}
|
||||
|
||||
mEdgeView.onRender(canvas);
|
||||
super.render(canvas);
|
||||
mEdgeView.render(canvas);
|
||||
}
|
||||
|
||||
public GalleryPageView obtainPage() {
|
||||
@@ -436,6 +428,8 @@ public class GalleryView extends GLView implements GestureRecognizer.Listener {
|
||||
|
||||
public abstract void onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY);
|
||||
|
||||
public abstract boolean canScale();
|
||||
|
||||
public abstract void onScale(float focusX, float focusY, float scale);
|
||||
|
||||
public abstract boolean onUpdateAnimation(long time);
|
||||
|
||||
@@ -39,7 +39,7 @@ public class ImageView extends GLView {
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
public @interface StartPosition {}
|
||||
|
||||
// TODO adjust scale max and min accroding to image size and screen size
|
||||
// TODO adjust scale max and min according to image size and screen size
|
||||
private static final float SCALE_MIN = 1 / 10.0f;
|
||||
private static final float SCALE_MAX = 10.0f;
|
||||
|
||||
@@ -100,6 +100,83 @@ public class ImageView extends GLView {
|
||||
mPositionInRootDirty = true;
|
||||
}
|
||||
|
||||
public boolean isLoaded() {
|
||||
return mTexture != null;
|
||||
}
|
||||
|
||||
public boolean canFlingVertically() {
|
||||
if (mScaleOffsetDirty) {
|
||||
setScaleOffset(mScaleMode, mStartPosition, mScaleValue);
|
||||
if (mScaleOffsetDirty) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return mDst.top < 0.0f || mDst.bottom > getHeight();
|
||||
}
|
||||
|
||||
public boolean canFlingHorizontally() {
|
||||
if (mScaleOffsetDirty) {
|
||||
setScaleOffset(mScaleMode, mStartPosition, mScaleValue);
|
||||
if (mScaleOffsetDirty) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return mDst.left < 0.0f || mDst.right > getWidth();
|
||||
}
|
||||
|
||||
public boolean canFling() {
|
||||
if (mScaleOffsetDirty) {
|
||||
setScaleOffset(mScaleMode, mStartPosition, mScaleValue);
|
||||
if (mScaleOffsetDirty) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return mDst.left < 0.0f || mDst.top < 0.0f || mDst.right > getWidth() || mDst.bottom > getHeight();
|
||||
}
|
||||
|
||||
public int getMaxDx() {
|
||||
if (mScaleOffsetDirty) {
|
||||
setScaleOffset(mScaleMode, mStartPosition, mScaleValue);
|
||||
if (mScaleOffsetDirty) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return Math.max(0, -(int) mDst.left);
|
||||
}
|
||||
|
||||
public int getMinDx() {
|
||||
if (mScaleOffsetDirty) {
|
||||
setScaleOffset(mScaleMode, mStartPosition, mScaleValue);
|
||||
if (mScaleOffsetDirty) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return Math.min(0, getWidth() - (int) mDst.right);
|
||||
}
|
||||
|
||||
public int getMaxDy() {
|
||||
if (mScaleOffsetDirty) {
|
||||
setScaleOffset(mScaleMode, mStartPosition, mScaleValue);
|
||||
if (mScaleOffsetDirty) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return Math.max(0, -(int) mDst.top);
|
||||
}
|
||||
|
||||
public int getMinDy() {
|
||||
if (mScaleOffsetDirty) {
|
||||
setScaleOffset(mScaleMode, mStartPosition, mScaleValue);
|
||||
if (mScaleOffsetDirty) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return Math.min(0, getHeight() - (int) mDst.bottom);
|
||||
}
|
||||
|
||||
/**
|
||||
* If target is shorter then screen, make it in screen center. If target is
|
||||
* longer then parent, make sure target fill parent over
|
||||
@@ -251,7 +328,6 @@ public class ImageView extends GLView {
|
||||
mPositionInRootDirty = true;
|
||||
}
|
||||
|
||||
|
||||
public void scroll(int dx, int dy, int[] remain) {
|
||||
// Only work after layout
|
||||
if (mScaleOffsetDirty) {
|
||||
@@ -367,6 +443,8 @@ public class ImageView extends GLView {
|
||||
srcActual.setEmpty();
|
||||
dstActual.setEmpty();
|
||||
}
|
||||
|
||||
mPositionInRootDirty = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -381,7 +459,6 @@ public class ImageView extends GLView {
|
||||
}
|
||||
|
||||
if (mPositionInRootDirty) {
|
||||
mPositionInRootDirty = false;
|
||||
applyPositionInRoot();
|
||||
} else {
|
||||
mSrcActual.set(0, 0, texture.getWidth(), texture.getHeight());
|
||||
|
||||
@@ -16,9 +16,9 @@
|
||||
|
||||
package com.hippo.ehviewer.ui.gl;
|
||||
|
||||
import android.content.Context;
|
||||
import android.support.annotation.IntDef;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.util.Log;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.animation.Interpolator;
|
||||
|
||||
@@ -70,10 +70,17 @@ public class PagerLayoutManager extends GalleryView.LayoutManager {
|
||||
private int mDeltaX;
|
||||
private int mDeltaY;
|
||||
|
||||
public PagerLayoutManager(@NonNull GalleryView galleryView, int interval, int progressSize) {
|
||||
private PageFling mPageFling;
|
||||
private SmoothScroller mSmoothScroller;
|
||||
|
||||
public PagerLayoutManager(Context context, @NonNull GalleryView galleryView,
|
||||
int interval, int progressSize) {
|
||||
super(galleryView);
|
||||
mInterval = interval;
|
||||
mProgressSpec = GLView.MeasureSpec.makeMeasureSpec(progressSize, GLView.MeasureSpec.EXACTLY);
|
||||
|
||||
mPageFling = new PageFling(context);
|
||||
mSmoothScroller = new SmoothScroller();
|
||||
}
|
||||
|
||||
public void setMode(@Mode int mode) {
|
||||
@@ -255,11 +262,30 @@ public class PagerLayoutManager extends GalleryView.LayoutManager {
|
||||
public void onDown() {
|
||||
mDeltaX = 0;
|
||||
mDeltaY = 0;
|
||||
|
||||
mSmoothScroller.cancel();
|
||||
mPageFling.cancel();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUp() {
|
||||
mGalleryView.getEdgeView().onRelease();
|
||||
|
||||
// Scroll
|
||||
if (mOffset != 0) {
|
||||
int width = mGalleryView.getWidth();
|
||||
int dx;
|
||||
if (mOffset >= mInterval && getLeftPage() != null) {
|
||||
dx = mOffset - width - mInterval;
|
||||
} else if (mOffset <= -mInterval && getRightPage() != null) {
|
||||
dx = mOffset + width + mInterval;
|
||||
} else {
|
||||
dx = mOffset;
|
||||
}
|
||||
final float pageDelta = 7 * (float) Math.abs(mOffset) / (width + mInterval);
|
||||
int duration = (int) ((pageDelta + 1) * 100);
|
||||
mSmoothScroller.startSmoothScroll(dx, 0, duration);
|
||||
}
|
||||
}
|
||||
|
||||
private void pagePrevious() {
|
||||
@@ -303,9 +329,9 @@ public class PagerLayoutManager extends GalleryView.LayoutManager {
|
||||
if (iterator.hasNext()) {
|
||||
iterator.mark();
|
||||
iterator.next();
|
||||
mPrevious = mGalleryView.obtainPage();
|
||||
iterator.bind(mPrevious);
|
||||
mGalleryView.addComponent(mPrevious);
|
||||
mNext = mGalleryView.obtainPage();
|
||||
iterator.bind(mNext);
|
||||
mGalleryView.addComponent(mNext);
|
||||
iterator.reset();
|
||||
}
|
||||
}
|
||||
@@ -341,31 +367,41 @@ public class PagerLayoutManager extends GalleryView.LayoutManager {
|
||||
|
||||
int remain;
|
||||
if (dx < 0) { // Try to show left
|
||||
int limit;
|
||||
if (leftPage == null) {
|
||||
return dx;
|
||||
limit = 0;
|
||||
} else {
|
||||
limit = width + mInterval;
|
||||
}
|
||||
|
||||
if (dx > mOffset - width - mInterval) {
|
||||
if (dx > mOffset - limit) {
|
||||
remain = 0;
|
||||
mOffset -= dx;
|
||||
} else {
|
||||
// Go to left page
|
||||
pageLeft();
|
||||
remain = dx + width + mInterval - mOffset;
|
||||
// Go to left page if left page not null
|
||||
if (leftPage != null) {
|
||||
pageLeft();
|
||||
}
|
||||
remain = dx + limit - mOffset;
|
||||
mOffset = 0;
|
||||
}
|
||||
} else { // Try to show right
|
||||
int limit;
|
||||
if (rightPage == null) {
|
||||
return dx;
|
||||
limit = 0;
|
||||
} else {
|
||||
limit = - width - mInterval;
|
||||
}
|
||||
|
||||
if (dx < width + mInterval + mOffset) {
|
||||
if (dx < mOffset - limit) {
|
||||
remain = 0;
|
||||
mOffset -= dx;
|
||||
} else {
|
||||
// Go to right page
|
||||
pageRight();
|
||||
remain = dx - width - mInterval - mOffset;
|
||||
// Go to right page if right page not null
|
||||
if (rightPage != null) {
|
||||
pageRight();
|
||||
}
|
||||
remain = dx + limit - mOffset;
|
||||
mOffset = 0;
|
||||
}
|
||||
}
|
||||
@@ -373,7 +409,7 @@ public class PagerLayoutManager extends GalleryView.LayoutManager {
|
||||
return remain;
|
||||
}
|
||||
|
||||
public void overScrollEdge(float x, float y, int dx, int dy) {
|
||||
public void overScrollEdge(int dx, int dy, float x, float y) {
|
||||
GLEdgeView edgeView = mGalleryView.getEdgeView();
|
||||
|
||||
mDeltaX += dx;
|
||||
@@ -391,11 +427,22 @@ public class PagerLayoutManager extends GalleryView.LayoutManager {
|
||||
}
|
||||
}
|
||||
|
||||
// TODO What about top and bottom
|
||||
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, y, GLEdgeView.BOTTOM);
|
||||
if (!edgeView.isFinished(GLEdgeView.TOP)) {
|
||||
edgeView.onRelease(GLEdgeView.TOP);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onScroll(float dx, float dy, float totalX, float totalY, float x, float y) {
|
||||
public void scrollInternal(float dx, float dy, float x, float y) {
|
||||
if (mCurrent == null) {
|
||||
return;
|
||||
}
|
||||
@@ -422,7 +469,7 @@ public class PagerLayoutManager extends GalleryView.LayoutManager {
|
||||
(getLeftPage() == null && mOffset == 0 && remainX < 0) ||
|
||||
(getRightPage() == null && mOffset == 0 && remainX > 0)) {
|
||||
// On edge
|
||||
overScrollEdge(x, y, remainX, remainY);
|
||||
overScrollEdge(remainX, remainY, x, y);
|
||||
remainX = 0;
|
||||
remainY = 0;
|
||||
} else if (mCanScrollBetweenPages) {
|
||||
@@ -432,7 +479,6 @@ public class PagerLayoutManager extends GalleryView.LayoutManager {
|
||||
mDeltaX = 0;
|
||||
mDeltaY = 0;
|
||||
} else {
|
||||
Log.w(TAG, "Something wrong?");
|
||||
remainX = 0;
|
||||
remainY = 0;
|
||||
mDeltaX = 0;
|
||||
@@ -445,14 +491,26 @@ public class PagerLayoutManager extends GalleryView.LayoutManager {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onScroll(float dx, float dy, float totalX, float totalY, float x, float y) {
|
||||
scrollInternal(dx, dy, x, y);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
|
||||
if (mCurrent == null) {
|
||||
if (mCurrent == null || mOffset != 0 || !mCurrent.getImageView().isLoaded() ||
|
||||
!mCurrent.getImageView().canFling()) {
|
||||
return;
|
||||
}
|
||||
|
||||
ImageView image = mCurrent.getImageView();
|
||||
mPageFling.startFling((int) velocityX, image.getMinDx(), image.getMaxDx(),
|
||||
(int) velocityY, image.getMinDy(), image.getMaxDy());
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean canScale() {
|
||||
return mCurrent != null && mOffset == 0 && mCurrent.getImageView().isLoaded();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -461,22 +519,17 @@ public class PagerLayoutManager extends GalleryView.LayoutManager {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
mCurrent.getImageView().scale(focusX, focusY, scale);
|
||||
// TODO Save scale
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onUpdateAnimation(long time) {
|
||||
return false;
|
||||
boolean invalidate = mSmoothScroller.calculate(time);
|
||||
invalidate |= mPageFling.calculate(time);
|
||||
return invalidate;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class SmoothScroller extends Animation {
|
||||
|
||||
private int mDx;
|
||||
@@ -484,6 +537,10 @@ public class PagerLayoutManager extends GalleryView.LayoutManager {
|
||||
private int mLastX;
|
||||
private int mLastY;
|
||||
|
||||
public SmoothScroller() {
|
||||
setInterpolator(SMOOTH_SCROLLER_INTERPOLATOR);
|
||||
}
|
||||
|
||||
public void startSmoothScroll(int dx, int dy, int duration) {
|
||||
mDx = dx;
|
||||
mDy = dy;
|
||||
@@ -491,7 +548,7 @@ public class PagerLayoutManager extends GalleryView.LayoutManager {
|
||||
mLastY = 0;
|
||||
setDuration(duration);
|
||||
start();
|
||||
// TODO invalidate();
|
||||
mGalleryView.invalidate();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -501,16 +558,105 @@ public class PagerLayoutManager extends GalleryView.LayoutManager {
|
||||
int offsetX = x - mLastX;
|
||||
while (offsetX != 0) {
|
||||
int oldOffsetX = offsetX;
|
||||
// TODO offsetX = scrollBetweenPagesHMode(offsetX);
|
||||
offsetX = scrollBetweenPages(offsetX);
|
||||
// Avoid loop infinitely
|
||||
if (offsetX == oldOffsetX) {
|
||||
break;
|
||||
} else {
|
||||
// TODO mRequestFill = true;
|
||||
mGalleryView.requestFill();
|
||||
}
|
||||
}
|
||||
mLastX = x;
|
||||
mLastY = y;
|
||||
}
|
||||
}
|
||||
|
||||
class PageFling extends Fling {
|
||||
|
||||
private int mVelocityX;
|
||||
private int mVelocityY;
|
||||
private int mDx;
|
||||
private int mDy;
|
||||
private int mLastX;
|
||||
private int mLastY;
|
||||
private int[] mTemp = new int[2];
|
||||
|
||||
public PageFling(Context context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
public void startFling(int velocityX, int minX, int maxX,
|
||||
int velocityY, int minY, int maxY) {
|
||||
mVelocityX = velocityX;
|
||||
mVelocityY = velocityY;
|
||||
mDx = (int) (getSplineFlingDistance(velocityX) * Math.signum(velocityX));
|
||||
mDy = (int) (getSplineFlingDistance(velocityY) * Math.signum(velocityY));
|
||||
mLastX = 0;
|
||||
mLastY = 0;
|
||||
int durationX = getSplineFlingDuration(velocityX);
|
||||
int durationY = getSplineFlingDuration(velocityY);
|
||||
|
||||
if (mDx < minX) {
|
||||
durationX = adjustDuration(0, mDx, minX, durationX);
|
||||
mDx = minX;
|
||||
}
|
||||
if (mDx > maxX) {
|
||||
durationX = adjustDuration(0, mDx, maxX, durationX);
|
||||
mDx = maxX;
|
||||
}
|
||||
if (mDy < minY) {
|
||||
durationY = adjustDuration(0, mDy, minY, durationY);
|
||||
mDy = minY;
|
||||
}
|
||||
if (mDy > maxY) {
|
||||
durationY = adjustDuration(0, mDy, maxY, durationY);
|
||||
mDy = maxY;
|
||||
}
|
||||
|
||||
setDuration(Math.max(durationX, durationY));
|
||||
start();
|
||||
mGalleryView.invalidate();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onCalculate(float progress) {
|
||||
int x = (int) (mDx * progress);
|
||||
int y = (int) (mDy * progress);
|
||||
int offsetX = x - mLastX;
|
||||
int offsetY = y - mLastY;
|
||||
if (mCurrent != null && (offsetX != 0 || offsetY != 0)) {
|
||||
mCurrent.getImageView().scroll(-offsetX, -offsetY, mTemp);
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -60,6 +60,11 @@ public class ScrollLayoutManager extends GalleryView.LayoutManager {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canScale() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onScale(float focusX, float focusY, float scale) {
|
||||
|
||||
|
||||
@@ -125,11 +125,11 @@ abstract public class Animation {
|
||||
return mStartTime != NO_ANIMATION;
|
||||
}
|
||||
|
||||
public void forceStop() {
|
||||
public void cancel() {
|
||||
mStartTime = NO_ANIMATION;
|
||||
}
|
||||
|
||||
public void forceReset() {
|
||||
public void reset() {
|
||||
mStartTime = ANIMATION_START;
|
||||
mRunnedCount = 0;
|
||||
mLastFrameTime = 0;
|
||||
@@ -153,6 +153,7 @@ abstract public class Animation {
|
||||
if (elapse >= mDuration) {
|
||||
mRunnedCount++;
|
||||
if (mRunnedCount >= mRepeatCount && mRepeatCount != INFINITE) {
|
||||
onFinish();
|
||||
mStartTime = NO_ANIMATION;
|
||||
} else {
|
||||
mStartTime += elapse;
|
||||
@@ -163,4 +164,7 @@ abstract public class Animation {
|
||||
}
|
||||
|
||||
abstract protected void onCalculate(float progress);
|
||||
|
||||
protected void onFinish() {
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* 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.gl.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
@Target({ElementType.METHOD, ElementType.CONSTRUCTOR, ElementType.TYPE})
|
||||
public @interface RenderThread {
|
||||
}
|
||||
@@ -19,14 +19,13 @@ package com.hippo.gl.glrenderer;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.RectF;
|
||||
import android.os.Process;
|
||||
import android.os.SystemClock;
|
||||
import android.support.annotation.IntDef;
|
||||
import android.support.annotation.NonNull;
|
||||
|
||||
import com.hippo.gl.image.AnimatedImage;
|
||||
import com.hippo.gl.image.Image;
|
||||
import com.hippo.gl.annotation.RenderThread;
|
||||
import com.hippo.gl.view.GLRoot;
|
||||
import com.hippo.image.Image;
|
||||
import com.hippo.yorozuya.InfiniteThreadExecutor;
|
||||
import com.hippo.yorozuya.PVLock;
|
||||
import com.hippo.yorozuya.PriorityThreadFactory;
|
||||
@@ -39,12 +38,12 @@ import java.util.concurrent.LinkedBlockingQueue;
|
||||
|
||||
public class ImageTexture implements Texture {
|
||||
|
||||
@IntDef({SMALL, LARGE})
|
||||
@IntDef({TILE_SMALL, TILE_LARGE})
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
private @interface Size {}
|
||||
private @interface TileType {}
|
||||
|
||||
private static final int SMALL = 0;
|
||||
private static final int LARGE = 1;
|
||||
private static final int TILE_SMALL = 0;
|
||||
private static final int TILE_LARGE = 1;
|
||||
|
||||
private static final int SMALL_CONTENT_SIZE = 254;
|
||||
private static final int SMALL_BORDER_SIZE = 1;
|
||||
@@ -62,7 +61,6 @@ public class ImageTexture implements Texture {
|
||||
|
||||
private static Bitmap sSmallUploadBitmap;
|
||||
private static Bitmap sLargeUploadBitmap;
|
||||
|
||||
private static InfiniteThreadExecutor sThreadExecutor;
|
||||
private static PVLock sPVLock;
|
||||
|
||||
@@ -70,21 +68,6 @@ public class ImageTexture implements Texture {
|
||||
private static Tile sLargeFreeTileHead = null;
|
||||
private static final Object sFreeTileLock = new Object();
|
||||
|
||||
public static void prepareResources() {
|
||||
sSmallUploadBitmap = Bitmap.createBitmap(SMALL_TILE_SIZE, SMALL_TILE_SIZE, Bitmap.Config.ARGB_8888);
|
||||
sLargeUploadBitmap = Bitmap.createBitmap(LARGE_TILE_SIZE, LARGE_TILE_SIZE, Bitmap.Config.ARGB_8888);
|
||||
sThreadExecutor = new InfiniteThreadExecutor(3000, new LinkedBlockingQueue<Runnable>(),
|
||||
new PriorityThreadFactory(ImageTexture.class.getSimpleName(), Process.THREAD_PRIORITY_BACKGROUND));
|
||||
sPVLock = new PVLock(3);
|
||||
}
|
||||
|
||||
public static void freeResources() {
|
||||
sSmallUploadBitmap = null;
|
||||
sLargeUploadBitmap = null;
|
||||
sThreadExecutor = null;
|
||||
sPVLock = null;
|
||||
}
|
||||
|
||||
private final Image mImage;
|
||||
private int mUploadIndex = 0;
|
||||
private final Tile[] mTiles; // Can be modified in different threads.
|
||||
@@ -95,12 +78,17 @@ public class ImageTexture implements Texture {
|
||||
private final RectF mSrcRect = new RectF();
|
||||
private final RectF mDestRect = new RectF();
|
||||
|
||||
private boolean mRecycled = false;
|
||||
private boolean mRecycleLock = false;
|
||||
private boolean mPause = false;
|
||||
private volatile boolean mConfirmFrame = false;
|
||||
private int mTargetFrame = -1;
|
||||
private Callback mCallback;
|
||||
private volatile boolean mFrameDirty = false;
|
||||
|
||||
|
||||
static {
|
||||
sSmallUploadBitmap = Bitmap.createBitmap(SMALL_TILE_SIZE, SMALL_TILE_SIZE, Bitmap.Config.ARGB_8888);
|
||||
sLargeUploadBitmap = Bitmap.createBitmap(LARGE_TILE_SIZE, LARGE_TILE_SIZE, Bitmap.Config.ARGB_8888);
|
||||
sThreadExecutor = new InfiniteThreadExecutor(3000, new LinkedBlockingQueue<Runnable>(),
|
||||
new PriorityThreadFactory(ImageTexture.class.getSimpleName(),
|
||||
android.os.Process.THREAD_PRIORITY_BACKGROUND));
|
||||
sPVLock = new PVLock(3);
|
||||
}
|
||||
|
||||
public static class Uploader implements GLRoot.OnGLIdleListener {
|
||||
private final ArrayDeque<ImageTexture> mTextures =
|
||||
@@ -150,7 +138,8 @@ public class ImageTexture implements Texture {
|
||||
|
||||
private static class Tile extends UploadedTexture {
|
||||
|
||||
private int mSize;
|
||||
@TileType
|
||||
private int mTileType;
|
||||
public int offsetX;
|
||||
public int offsetY;
|
||||
public Image image;
|
||||
@@ -161,18 +150,18 @@ public class ImageTexture implements Texture {
|
||||
public int tileSize;
|
||||
public Bitmap uploadBitmap;
|
||||
|
||||
public void setSize(@Size int size, int width, int height) {
|
||||
mSize = size;
|
||||
if (size == SMALL) {
|
||||
public void setSize(@TileType int tileType, int width, int height) {
|
||||
mTileType = tileType;
|
||||
if (tileType == TILE_SMALL) {
|
||||
borderSize = SMALL_BORDER_SIZE;
|
||||
tileSize = SMALL_TILE_SIZE;
|
||||
uploadBitmap = sSmallUploadBitmap;
|
||||
} else if (size == LARGE) {
|
||||
} else if (tileType == TILE_LARGE) {
|
||||
borderSize = LARGE_BORDER_SIZE;
|
||||
tileSize = LARGE_TILE_SIZE;
|
||||
uploadBitmap = sLargeUploadBitmap;
|
||||
} else {
|
||||
throw new IllegalStateException("Not support size " + size);
|
||||
throw new IllegalStateException("Not support tile type: " + tileType);
|
||||
}
|
||||
contentWidth = width;
|
||||
contentHeight = height;
|
||||
@@ -188,8 +177,29 @@ public class ImageTexture implements Texture {
|
||||
final Image image = this.image;
|
||||
if (image != null) {
|
||||
synchronized (image) {
|
||||
image.copyPixels(offsetX - borderSize, offsetY - borderSize, uploadBitmap,
|
||||
0, 0, tileSize, tileSize, Color.TRANSPARENT);
|
||||
int srcX;
|
||||
int dstX;
|
||||
if (offsetX - borderSize < 0) {
|
||||
srcX = 0;
|
||||
dstX = borderSize - offsetX;
|
||||
} else {
|
||||
srcX = offsetX - borderSize;
|
||||
dstX = 0;
|
||||
}
|
||||
int srcY;
|
||||
int dstY;
|
||||
if (offsetY - borderSize < 0) {
|
||||
srcY = 0;
|
||||
dstY = borderSize - offsetY;
|
||||
} else {
|
||||
srcY = offsetY - borderSize;
|
||||
dstY = 0;
|
||||
}
|
||||
|
||||
image.render(srcX, srcY, uploadBitmap, dstX, dstY,
|
||||
Math.min(image.getWidth() - srcX, tileSize - dstX),
|
||||
Math.min(image.getHeight() - srcY, tileSize - dstY),
|
||||
true, Color.TRANSPARENT);
|
||||
}
|
||||
}
|
||||
return uploadBitmap;
|
||||
@@ -224,15 +234,31 @@ public class ImageTexture implements Texture {
|
||||
}
|
||||
|
||||
public void free() {
|
||||
switch (mSize) {
|
||||
case SMALL:
|
||||
switch (mTileType) {
|
||||
case TILE_SMALL:
|
||||
freeSmallTile(this);
|
||||
break;
|
||||
case LARGE:
|
||||
case TILE_LARGE:
|
||||
freeLargeTile(this);
|
||||
break;
|
||||
default:
|
||||
throw new IllegalStateException("Not support size " + mSize);
|
||||
throw new IllegalStateException("Not support tile type: " + mTileType);
|
||||
}
|
||||
}
|
||||
|
||||
private static void freeSmallTile(Tile tile) {
|
||||
tile.invalidate();
|
||||
synchronized (sFreeTileLock) {
|
||||
tile.nextFreeTile = sSmallFreeTileHead;
|
||||
sSmallFreeTileHead = tile;
|
||||
}
|
||||
}
|
||||
|
||||
private static void freeLargeTile(Tile tile) {
|
||||
tile.invalidate();
|
||||
synchronized (sFreeTileLock) {
|
||||
tile.nextFreeTile = sLargeFreeTileHead;
|
||||
sLargeFreeTileHead = tile;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -263,20 +289,69 @@ public class ImageTexture implements Texture {
|
||||
}
|
||||
}
|
||||
|
||||
private static void freeSmallTile(Tile tile) {
|
||||
tile.invalidate();
|
||||
synchronized (sFreeTileLock) {
|
||||
tile.nextFreeTile = sSmallFreeTileHead;
|
||||
sSmallFreeTileHead = tile;
|
||||
}
|
||||
}
|
||||
public ImageTexture(@NonNull Image image) {
|
||||
mImage = image;
|
||||
int width = mWidth = image.getWidth();
|
||||
int height = mHeight = image.getHeight();
|
||||
ArrayList<Tile> list = new ArrayList<>();
|
||||
|
||||
private static void freeLargeTile(Tile tile) {
|
||||
tile.invalidate();
|
||||
synchronized (sFreeTileLock) {
|
||||
tile.nextFreeTile = sLargeFreeTileHead;
|
||||
sLargeFreeTileHead = tile;
|
||||
for (int x = 0; x < width; x += LARGE_CONTENT_SIZE) {
|
||||
for (int y = 0; y < height; y += LARGE_CONTENT_SIZE) {
|
||||
int w = Math.min(LARGE_CONTENT_SIZE, width - x);
|
||||
int h = Math.min(LARGE_CONTENT_SIZE, height - y);
|
||||
|
||||
if (w <= SMALL_CONTENT_SIZE) {
|
||||
Tile tile = obtainSmallTile();
|
||||
tile.offsetX = x;
|
||||
tile.offsetY = y;
|
||||
tile.image = image;
|
||||
tile.setSize(TILE_SMALL, w, Math.min(SMALL_CONTENT_SIZE, h));
|
||||
list.add(tile);
|
||||
|
||||
int nextHeight = h - SMALL_CONTENT_SIZE;
|
||||
if (nextHeight > 0) {
|
||||
Tile nextTile = obtainSmallTile();
|
||||
nextTile.offsetX = x;
|
||||
nextTile.offsetY = y + SMALL_CONTENT_SIZE;
|
||||
nextTile.image = image;
|
||||
nextTile.setSize(TILE_SMALL, w, nextHeight);
|
||||
list.add(nextTile);
|
||||
}
|
||||
} else if (h <= SMALL_CONTENT_SIZE) {
|
||||
Tile tile = obtainSmallTile();
|
||||
tile.offsetX = x;
|
||||
tile.offsetY = y;
|
||||
tile.image = image;
|
||||
tile.setSize(TILE_SMALL, Math.min(SMALL_CONTENT_SIZE, w), h);
|
||||
list.add(tile);
|
||||
|
||||
int nextWidth = w - SMALL_CONTENT_SIZE;
|
||||
if (nextWidth > 0) {
|
||||
Tile nextTile = obtainSmallTile();
|
||||
nextTile.offsetX = x + SMALL_CONTENT_SIZE;
|
||||
nextTile.offsetY = y;
|
||||
nextTile.image = image;
|
||||
nextTile.setSize(TILE_SMALL, nextWidth, h);
|
||||
list.add(nextTile);
|
||||
}
|
||||
} else {
|
||||
Tile tile = obtainLargeTile();
|
||||
tile.offsetX = x;
|
||||
tile.offsetY = y;
|
||||
tile.image = image;
|
||||
tile.setSize(TILE_LARGE, w, h);
|
||||
list.add(tile);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mTiles = list.toArray(new Tile[list.size()]);
|
||||
|
||||
/*
|
||||
if (image instanceof AnimatedImage) {
|
||||
sThreadExecutor.execute(new DecodeTask());
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
private boolean uploadNextTile(GLCanvas canvas) {
|
||||
@@ -301,195 +376,6 @@ public class ImageTexture implements Texture {
|
||||
return mUploadIndex == mTiles.length;
|
||||
}
|
||||
|
||||
private class DecodeTask implements Runnable {
|
||||
|
||||
private boolean checkRecycle() {
|
||||
if (mRecycled) {
|
||||
if (!mImage.isRecycled()) {
|
||||
mImage.recycle();
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
synchronized (mImage) {
|
||||
if (checkRecycle()) {
|
||||
return;
|
||||
}
|
||||
mRecycleLock = true;
|
||||
}
|
||||
|
||||
AnimatedImage aImage = (AnimatedImage) mImage;
|
||||
|
||||
// Avoid a lot of decode thread at same time
|
||||
sPVLock.p();
|
||||
boolean decode = aImage.decode();
|
||||
sPVLock.v();
|
||||
|
||||
synchronized (mImage) {
|
||||
mRecycleLock = false;
|
||||
if (checkRecycle()) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// No need to do animate if decode failed
|
||||
if (!decode) {
|
||||
return;
|
||||
}
|
||||
|
||||
long delay;
|
||||
long time;
|
||||
int frame = aImage.getCurrentFrame();
|
||||
int frameCount = aImage.getFrameCount();
|
||||
long forecast = System.currentTimeMillis();
|
||||
|
||||
// No need to do animate if only on frame
|
||||
if (frameCount <= 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
while (true) {
|
||||
synchronized (mImage) {
|
||||
// Check recycle and unlock recycle
|
||||
mRecycleLock = false;
|
||||
if (checkRecycle()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Check pause
|
||||
while (mPause && mTargetFrame == -1) {
|
||||
try {
|
||||
mImage.wait();
|
||||
} catch (InterruptedException e) {
|
||||
// Ignore
|
||||
}
|
||||
mPause = false;
|
||||
|
||||
// Check recycle
|
||||
if (checkRecycle()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Update forecast
|
||||
forecast = System.currentTimeMillis();
|
||||
}
|
||||
|
||||
// Get next frame and delay
|
||||
time = System.currentTimeMillis();
|
||||
if (mTargetFrame == -1) {
|
||||
frame = (frame + 1) % frameCount;
|
||||
delay = aImage.getDelay(frame) - (time - forecast);
|
||||
} else {
|
||||
frame = mTargetFrame;
|
||||
delay = 0;
|
||||
mTargetFrame = -1;
|
||||
}
|
||||
forecast = time + delay;
|
||||
}
|
||||
|
||||
// Do sleep
|
||||
if (delay > 0) {
|
||||
try {
|
||||
Thread.sleep(delay);
|
||||
} catch (InterruptedException e) {
|
||||
// Ignore
|
||||
}
|
||||
}
|
||||
|
||||
// Check recycle and lock recycle
|
||||
synchronized (mImage) {
|
||||
if (checkRecycle()) {
|
||||
return;
|
||||
}
|
||||
mRecycleLock = true;
|
||||
}
|
||||
|
||||
aImage.setCurrentFrame(frame);
|
||||
mConfirmFrame = true;
|
||||
|
||||
// Notify
|
||||
Callback callback = mCallback;
|
||||
if (callback != null) {
|
||||
callback.invalidateImage(mImage);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public ImageTexture(@NonNull Image image) {
|
||||
mImage = image;
|
||||
int width = mWidth = image.getWidth();
|
||||
int height = mHeight = image.getHeight();
|
||||
ArrayList<Tile> list = new ArrayList<>();
|
||||
|
||||
for (int x = 0; x < width; x += LARGE_CONTENT_SIZE) {
|
||||
for (int y = 0; y < height; y += LARGE_CONTENT_SIZE) {
|
||||
int w = Math.min(LARGE_CONTENT_SIZE, width - x);
|
||||
int h = Math.min(LARGE_CONTENT_SIZE, height - y);
|
||||
|
||||
if (w <= SMALL_TILE_SIZE) {
|
||||
Tile tile = obtainSmallTile();
|
||||
tile.offsetX = x;
|
||||
tile.offsetY = y;
|
||||
tile.image = image;
|
||||
tile.setSize(SMALL, w, Math.min(SMALL_TILE_SIZE, h));
|
||||
list.add(tile);
|
||||
|
||||
int nextHeight = h - SMALL_TILE_SIZE;
|
||||
if (nextHeight > 0) {
|
||||
Tile nextTile = obtainSmallTile();
|
||||
nextTile.offsetX = x;
|
||||
nextTile.offsetY = y + SMALL_TILE_SIZE;
|
||||
nextTile.image = image;
|
||||
nextTile.setSize(SMALL, w, nextHeight);
|
||||
list.add(nextTile);
|
||||
}
|
||||
|
||||
} else if (h <= SMALL_TILE_SIZE) {
|
||||
Tile tile = obtainSmallTile();
|
||||
tile.offsetX = x;
|
||||
tile.offsetY = y;
|
||||
tile.image = image;
|
||||
tile.setSize(SMALL, Math.min(SMALL_TILE_SIZE, w), h);
|
||||
list.add(tile);
|
||||
|
||||
int nextWidth = w - SMALL_TILE_SIZE;
|
||||
if (nextWidth > 0) {
|
||||
Tile nextTile = obtainSmallTile();
|
||||
nextTile.offsetX = x + SMALL_TILE_SIZE;
|
||||
nextTile.offsetY = y;
|
||||
nextTile.image = image;
|
||||
nextTile.setSize(SMALL, nextWidth, h);
|
||||
list.add(nextTile);
|
||||
}
|
||||
|
||||
} else {
|
||||
Tile tile = obtainLargeTile();
|
||||
tile.offsetX = x;
|
||||
tile.offsetY = y;
|
||||
tile.image = image;
|
||||
tile.setSize(LARGE, w, h);
|
||||
list.add(tile);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mTiles = list.toArray(new Tile[list.size()]);
|
||||
|
||||
if (image instanceof AnimatedImage) {
|
||||
sThreadExecutor.execute(new DecodeTask());
|
||||
}
|
||||
}
|
||||
|
||||
public void setCallback(Callback callback) {
|
||||
mCallback = callback;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getWidth() {
|
||||
return mWidth;
|
||||
@@ -522,9 +408,10 @@ public class ImageTexture implements Texture {
|
||||
y + (src.bottom - y0) * scaleY);
|
||||
}
|
||||
|
||||
@RenderThread
|
||||
private void syncFrame() {
|
||||
if (mConfirmFrame && mImage instanceof AnimatedImage) {
|
||||
mConfirmFrame = false;
|
||||
if (mFrameDirty) {
|
||||
mFrameDirty = false;
|
||||
|
||||
// invalid tiles
|
||||
for (int i = 0, n = mTiles.length; i < n; i++) {
|
||||
@@ -582,8 +469,9 @@ public class ImageTexture implements Texture {
|
||||
Tile t = mTiles[i];
|
||||
src.set(0, 0, t.contentWidth, t.contentHeight);
|
||||
src.offset(t.offsetX, t.offsetY);
|
||||
if (!src.intersect(source))
|
||||
if (!src.intersect(source)) {
|
||||
continue;
|
||||
}
|
||||
mapRect(dest, src, x0, y0, x, y, scaleX, scaleY);
|
||||
src.offset(t.borderSize - t.offsetX, t.borderSize - t.offsetY);
|
||||
canvas.drawTexture(t, src, dest);
|
||||
@@ -630,8 +518,9 @@ public class ImageTexture implements Texture {
|
||||
Tile t = mTiles[i];
|
||||
src.set(0, 0, t.contentWidth, t.contentHeight);
|
||||
src.offset(t.offsetX, t.offsetY);
|
||||
if (!src.intersect(source))
|
||||
if (!src.intersect(source)) {
|
||||
continue;
|
||||
}
|
||||
mapRect(dest, src, x0, y0, x, y, scaleX, scaleY);
|
||||
src.offset(t.borderSize - t.offsetX, t.borderSize - t.offsetY);
|
||||
canvas.drawMixed(t, color, ratio, src, dest);
|
||||
@@ -647,41 +536,4 @@ public class ImageTexture implements Texture {
|
||||
public boolean isReady() {
|
||||
return mUploadIndex == mTiles.length;
|
||||
}
|
||||
|
||||
public void setFrame(int frame) {
|
||||
synchronized (mImage) {
|
||||
mTargetFrame = frame;
|
||||
mImage.notify();
|
||||
}
|
||||
}
|
||||
|
||||
public void setPause(boolean pause) {
|
||||
synchronized (mImage) {
|
||||
mPause = pause;
|
||||
if (!pause) {
|
||||
mImage.notify();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Can be called in UI thread.
|
||||
public void recycle() {
|
||||
synchronized (mImage) {
|
||||
mRecycled = true;
|
||||
|
||||
for (int i = 0, n = mTiles.length; i < n; ++i) {
|
||||
mTiles[i].free();
|
||||
}
|
||||
|
||||
mImage.notify();
|
||||
|
||||
if (!mRecycleLock) {
|
||||
mImage.recycle();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public interface Callback {
|
||||
void invalidateImage(Image image);
|
||||
}
|
||||
}
|
||||
@@ -1,122 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 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
|
||||
*
|
||||
* 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.gl.image;
|
||||
|
||||
public class AnimatedImage extends Image {
|
||||
|
||||
private boolean mDecoded;
|
||||
private int mCurrentFrame;
|
||||
|
||||
private boolean mDirty = false;
|
||||
|
||||
protected AnimatedImage(long nativeImage, int format, int width, int height) {
|
||||
super(nativeImage, format, width, height);
|
||||
mCurrentFrame = 0;
|
||||
}
|
||||
|
||||
protected void checkDecoded() {
|
||||
if (!mDecoded) {
|
||||
throw new IllegalStateException("Call decode() first!");
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isDecoded() {
|
||||
checkRecycled();
|
||||
|
||||
return mDecoded;
|
||||
}
|
||||
|
||||
public boolean decode() {
|
||||
checkRecycled();
|
||||
|
||||
if (mDecoded) {
|
||||
return true;
|
||||
}
|
||||
if (mNativeImage != 0) {
|
||||
boolean result = nativeDecode(mNativeImage, mFormat);
|
||||
mDecoded = true;
|
||||
return result;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isAnimated() {
|
||||
checkRecycled();
|
||||
checkDecoded();
|
||||
|
||||
return getFrameCount() != 1;
|
||||
}
|
||||
|
||||
public int getFrameCount() {
|
||||
checkRecycled();
|
||||
checkDecoded();
|
||||
|
||||
return nativeGetFrameCount(mNativeImage, mFormat);
|
||||
}
|
||||
|
||||
public int getCurrentFrame() {
|
||||
checkRecycled();
|
||||
checkDecoded();
|
||||
|
||||
return mCurrentFrame;
|
||||
}
|
||||
|
||||
public void setCurrentFrame(int frame) {
|
||||
checkRecycled();
|
||||
checkDecoded();
|
||||
|
||||
int frameCount = getFrameCount();
|
||||
if (frame < 0 || frame >= frameCount) {
|
||||
throw new IndexOutOfBoundsException("Invalid frame " + frame + ", frame count is " + frameCount);
|
||||
}
|
||||
mCurrentFrame = frame;
|
||||
if (mNativeImage != 0) {
|
||||
nativeSetCurrentFrame(mNativeImage, mFormat, frame);
|
||||
mDirty = true;
|
||||
}
|
||||
}
|
||||
|
||||
public void advance() {
|
||||
setCurrentFrame((mCurrentFrame + 1) % getFrameCount());
|
||||
}
|
||||
|
||||
public int getCurrentDelay() {
|
||||
return getDelay(mCurrentFrame);
|
||||
}
|
||||
|
||||
public int getDelay(int frame) {
|
||||
checkRecycled();
|
||||
checkDecoded();
|
||||
|
||||
int frameCount = getFrameCount();
|
||||
if (frame < 0 || frame >= frameCount) {
|
||||
throw new IndexOutOfBoundsException("Invalid frame " + frame + ", frame count is " + frameCount);
|
||||
}
|
||||
return nativeGetDelay(mNativeImage, mFormat, frame);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void recycle() {
|
||||
super.recycle();
|
||||
}
|
||||
|
||||
private static native boolean nativeDecode(long nativeImage, int format);
|
||||
private static native int nativeGetFrameCount(long nativeImage, int format);
|
||||
private static native void nativeSetCurrentFrame(long nativeImage, int format, int frame);
|
||||
private static native int nativeGetDelay(long nativeImage, int format, int frame);
|
||||
}
|
||||
@@ -1,87 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 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
|
||||
*
|
||||
* 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.gl.image;
|
||||
|
||||
import android.graphics.Bitmap;
|
||||
|
||||
import com.hippo.yorozuya.io.InputStreamPipe;
|
||||
|
||||
public class Image {
|
||||
|
||||
protected long mNativeImage;
|
||||
|
||||
protected final int mFormat;
|
||||
protected final int mWidth;
|
||||
protected final int mHeight;
|
||||
|
||||
protected Image(long nativeImage, int format, int width, int height) {
|
||||
mNativeImage = nativeImage;
|
||||
mFormat = format;
|
||||
mWidth = width;
|
||||
mHeight = height;
|
||||
}
|
||||
|
||||
protected void checkRecycled() {
|
||||
if (mNativeImage == 0) {
|
||||
throw new IllegalStateException("Image is recycled");
|
||||
}
|
||||
}
|
||||
|
||||
public int getFormat() {
|
||||
return mFormat;
|
||||
}
|
||||
|
||||
public int getWidth() {
|
||||
return mWidth;
|
||||
}
|
||||
|
||||
public int getHeight() {
|
||||
return mHeight;
|
||||
}
|
||||
|
||||
public boolean copyPixels(int srcX, int srcY, Bitmap bitmap, int dstX, int dstY,
|
||||
int width, int height, int defaultColor) {
|
||||
checkRecycled();
|
||||
|
||||
return nativeCopyPixels(mNativeImage, mFormat, srcX, srcY, bitmap,
|
||||
dstX, dstY, width, height, defaultColor);
|
||||
}
|
||||
|
||||
public void recycle() {
|
||||
if (mNativeImage != 0) {
|
||||
nativeRecycle(mNativeImage, mFormat);
|
||||
mNativeImage = 0;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isRecycled() {
|
||||
return mNativeImage == 0;
|
||||
}
|
||||
|
||||
public static Image decodeStreamPipe(InputStreamPipe isPipe) {
|
||||
return nativeDecodeStreamPipe(isPipe);
|
||||
}
|
||||
|
||||
static {
|
||||
System.loadLibrary("image");
|
||||
}
|
||||
|
||||
private static native Image nativeDecodeStreamPipe(InputStreamPipe isPipe);
|
||||
private static native boolean nativeCopyPixels(long nativeImage, int format, int srcX, int srcY,
|
||||
Bitmap bitmap, int dstX, int dstY, int width, int height, int otherColor);
|
||||
private static native void nativeRecycle(long nativeImage, int format);
|
||||
}
|
||||
@@ -49,7 +49,7 @@ import java.util.ArrayList;
|
||||
public class GLView implements TouchOwner {
|
||||
private static final String TAG = "GLView";
|
||||
|
||||
private static final boolean DEBUG_DRAW_BOUNDS = false;
|
||||
private static final boolean DEBUG_DRAW_BOUNDS = true;
|
||||
|
||||
public static final int VISIBLE = 0;
|
||||
public static final int INVISIBLE = 1;
|
||||
@@ -86,7 +86,7 @@ public class GLView implements TouchOwner {
|
||||
/**
|
||||
* Position in root
|
||||
*/
|
||||
private final int[] mPosition = new int[2];
|
||||
private final int[] mPositionInRoot = new int[2];
|
||||
protected final Rect mPaddings = new Rect();
|
||||
|
||||
private GLRoot mRoot;
|
||||
@@ -429,7 +429,7 @@ public class GLView implements TouchOwner {
|
||||
}
|
||||
}
|
||||
|
||||
protected void render(GLCanvas canvas) {
|
||||
public void render(GLCanvas canvas) {
|
||||
// render background color
|
||||
if (Color.alpha(mBackgroundColor) != 0) {
|
||||
canvas.fillRect(0, 0, getWidth(), getHeight(), mBackgroundColor);
|
||||
@@ -626,10 +626,45 @@ public class GLView implements TouchOwner {
|
||||
final boolean forceLayout = (mViewFlags & FLAG_LAYOUT_REQUESTED) == FLAG_LAYOUT_REQUESTED;
|
||||
if (sizeChanged || forceLayout) {
|
||||
onLayout(sizeChanged, left, top, right, bottom);
|
||||
notifyPositionInRoot();
|
||||
} else {
|
||||
dispatchNotifyPositionInRoot();
|
||||
}
|
||||
mViewFlags &= ~FLAG_LAYOUT_REQUESTED;
|
||||
}
|
||||
|
||||
public void dispatchNotifyPositionInRoot() {
|
||||
if (notifyPositionInRoot()) {
|
||||
for (int i = 0, size = getComponentCount(); i < size; i++) {
|
||||
getComponent(i).dispatchNotifyPositionInRoot();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public boolean notifyPositionInRoot() {
|
||||
// Update position in root
|
||||
int[] position = mPositionInRoot;
|
||||
int oldX = position[0];
|
||||
int oldY = position[1];
|
||||
if (mParent == null) {
|
||||
position[0] = 0;
|
||||
position[1] = 0;
|
||||
} else {
|
||||
mParent.getPositionInRoot(position);
|
||||
// Apply offset in parent
|
||||
position[0] += mBounds.left;
|
||||
position[1] += mBounds.top;
|
||||
}
|
||||
int x = position[0];
|
||||
int y = position[1];
|
||||
if (x != oldX || y != oldY) {
|
||||
onPositionInRootChanged(x, y, oldX, oldY);
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean setBounds(int left, int top, int right, int bottom) {
|
||||
Rect bounds = mBounds;
|
||||
int oldW = bounds.right - bounds.left;
|
||||
@@ -644,25 +679,6 @@ public class GLView implements TouchOwner {
|
||||
onSizeChanged(newW, newH, oldW, oldH);
|
||||
}
|
||||
|
||||
// Update position in root
|
||||
int[] position = mPosition;
|
||||
int oldX = position[0];
|
||||
int oldY = position[1];
|
||||
if (mParent == null) {
|
||||
position[0] = 0;
|
||||
position[1] = 0;
|
||||
} else {
|
||||
mParent.getPositionInRoot(position);
|
||||
// Apply offset in parent
|
||||
position[0] += left;
|
||||
position[1] += top;
|
||||
}
|
||||
int x = position[0];
|
||||
int y = position[1];
|
||||
if (x != oldX || y != oldY) {
|
||||
onPositionInRootChanged(x, y, oldX, oldY);
|
||||
}
|
||||
|
||||
return sizeChanged;
|
||||
}
|
||||
|
||||
@@ -674,8 +690,8 @@ public class GLView implements TouchOwner {
|
||||
|
||||
public void getPositionInRoot(int[] position) {
|
||||
AssertUtils.assertEquals("position should be 2 length int array", position.length, 2);
|
||||
position[0] = mPosition[0];
|
||||
position[1] = mPosition[1];
|
||||
position[0] = mPositionInRoot[0];
|
||||
position[1] = mPositionInRoot[1];
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -689,8 +705,8 @@ public class GLView implements TouchOwner {
|
||||
return;
|
||||
}
|
||||
|
||||
int x = mPosition[0];
|
||||
int y = mPosition[1];
|
||||
int x = mPositionInRoot[0];
|
||||
int y = mPositionInRoot[1];
|
||||
rect.set(x, y, x + getWidth(), y + getHeight());
|
||||
if (!rect.intersect(0, 0, root.getWidth(), root.getHeight())) {
|
||||
rect.setEmpty();
|
||||
|
||||
@@ -96,8 +96,7 @@ public final class GLEdgeView extends GLView {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRender(GLCanvas canvas) {
|
||||
super.onRender(canvas);
|
||||
public void render(GLCanvas canvas) {
|
||||
boolean more = false;
|
||||
for (int i = 0; i < 4; i++) {
|
||||
canvas.save(GLCanvas.SAVE_FLAG_MATRIX);
|
||||
|
||||
@@ -135,14 +135,14 @@ public class GLProgressView extends GLView {
|
||||
private void startAnimations() {
|
||||
List<Animation> animations = mAnimations;
|
||||
for (int i = 0, n = animations.size(); i < n; i++) {
|
||||
animations.get(i).forceReset();
|
||||
animations.get(i).reset();
|
||||
}
|
||||
}
|
||||
|
||||
private void stopAnimations() {
|
||||
List<Animation> animations = mAnimations;
|
||||
for (int i = 0, n = animations.size(); i < n; i++) {
|
||||
animations.get(i).forceStop();
|
||||
animations.get(i).cancel();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -94,6 +94,10 @@ public class GLTextView extends GLView {
|
||||
|
||||
@Override
|
||||
public void onRender(GLCanvas canvas) {
|
||||
if (mTextTexture == null || mIndexes == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
Rect paddings = getPaddings();
|
||||
int x = getDefaultBegin(getWidth(), (int) mTextTexture.getTextWidth(mIndexes),
|
||||
paddings.left, paddings.right, Gravity.getPosition(mGravity, Gravity.HORIZONTAL));
|
||||
|
||||
Reference in new issue
Block a user