Add ScrollLayoutManager
This commit is contained in:
1 parent
9e6895b775
commit
33f86fd32b
14 files changed
+648
-171
No files matched your search
@@ -20,7 +20,6 @@ import android.os.Bundle;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.v7.app.AppCompatActivity;
|
||||
import android.view.KeyEvent;
|
||||
import android.view.MotionEvent;
|
||||
|
||||
import com.hippo.ehviewer.R;
|
||||
import com.hippo.ehviewer.ui.gl.GalleryPageView;
|
||||
@@ -28,7 +27,6 @@ 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;
|
||||
@@ -57,29 +55,6 @@ public class GalleryActivity extends AppCompatActivity {
|
||||
mUploader = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onGenericMotionEvent(MotionEvent event) {
|
||||
switch (Dpad.getDirectionPressed(event)) {
|
||||
case Dpad.LEFT:
|
||||
// TODO do something
|
||||
return true;
|
||||
case Dpad.UP:
|
||||
// TODO do something
|
||||
return true;
|
||||
case Dpad.RIGHT:
|
||||
// TODO do something
|
||||
return true;
|
||||
case Dpad.DOWN:
|
||||
// TODO do something
|
||||
return true;
|
||||
case Dpad.CENTER:
|
||||
// TODO do something
|
||||
return true;
|
||||
}
|
||||
|
||||
return super.onGenericMotionEvent(event);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onKeyDown(int keyCode, KeyEvent event) {
|
||||
// Check volume
|
||||
@@ -154,7 +129,7 @@ public class GalleryActivity extends AppCompatActivity {
|
||||
}
|
||||
|
||||
|
||||
private static final int MAX_SIZE = 10;
|
||||
private static final int MAX_SIZE = 2;
|
||||
|
||||
private class InvalidPageIterator implements GalleryView.PageIterator {
|
||||
|
||||
@@ -214,7 +189,7 @@ public class GalleryActivity extends AppCompatActivity {
|
||||
|
||||
@Override
|
||||
public void bind(GalleryPageView view) {
|
||||
//view.showImage();
|
||||
view.showImage();
|
||||
view.getImageView().setTexture(mImageTexture);
|
||||
}
|
||||
|
||||
@@ -223,5 +198,4 @@ public class GalleryActivity extends AppCompatActivity {
|
||||
view.getImageView().setTexture(null);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -91,8 +91,6 @@ public final class MainActivity extends StageActivity
|
||||
|
||||
@Override
|
||||
protected void onNewIntent(Intent intent) {
|
||||
Log.d("TAG", "onNewIntent");
|
||||
|
||||
super.onNewIntent(intent);
|
||||
if (!handleIntent(intent) && intent != null && Intent.ACTION_VIEW.equals(intent.getAction())) {
|
||||
Toast.makeText(this, R.string.error_cannot_parse_the_url, Toast.LENGTH_SHORT).show();
|
||||
@@ -100,9 +98,6 @@ public final class MainActivity extends StageActivity
|
||||
}
|
||||
|
||||
private void onInit() {
|
||||
Log.d("TAG", "onInit");
|
||||
|
||||
|
||||
Intent intent = getIntent();
|
||||
if (!handleIntent(intent)) {
|
||||
if (intent != null && Intent.ACTION_VIEW.equals(intent.getAction())) {
|
||||
|
||||
@@ -79,8 +79,8 @@ public class GalleryPageView extends GLFrameLayout {
|
||||
}
|
||||
|
||||
public void showImage() {
|
||||
//mImage.setVisibility(VISIBLE);
|
||||
//mInfo.setVisibility(INVISIBLE);
|
||||
mImage.setVisibility(VISIBLE);
|
||||
mInfo.setVisibility(INVISIBLE);
|
||||
}
|
||||
|
||||
public ImageView getImageView() {
|
||||
|
||||
@@ -65,6 +65,7 @@ public class GalleryView extends GLView implements GestureRecognizer.Listener {
|
||||
private static final int BACKGROUND_COLOR = 0xff212121;
|
||||
private static final int INTERVAL_IN_DP = 24;
|
||||
private static final int PROGRESS_SIZE_IN_DP = 48;
|
||||
private static final int PAGE_MIN_HEIGHT_IN_DP = 256;
|
||||
|
||||
private static final int PAGE_STATE_UNKNOWN_SEEN = 0;
|
||||
private static final int PAGE_STATE_SEEN = 1;
|
||||
@@ -96,6 +97,7 @@ public class GalleryView extends GLView implements GestureRecognizer.Listener {
|
||||
private GestureRecognizer mGestureRecognizer;
|
||||
|
||||
private LayoutManager mPagerLayoutManager;
|
||||
private LayoutManager mScrollLayoutManager;
|
||||
private LayoutManager mLayoutManager;
|
||||
|
||||
private Recycler mRecycler;
|
||||
@@ -103,6 +105,7 @@ public class GalleryView extends GLView implements GestureRecognizer.Listener {
|
||||
private GLProgressView mProgressCache;
|
||||
|
||||
private int mProgressColor;
|
||||
private int mPageMinHeight;
|
||||
|
||||
private boolean mEnableRequestLayout = true;
|
||||
|
||||
@@ -137,12 +140,14 @@ public class GalleryView extends GLView implements GestureRecognizer.Listener {
|
||||
mRecycler = new Recycler();
|
||||
|
||||
mProgressColor = ResourcesUtils.getAttrColor(context, R.attr.colorPrimary);
|
||||
mPageMinHeight = LayoutUtils.dp2pix(context, PAGE_MIN_HEIGHT_IN_DP);
|
||||
|
||||
int interval = LayoutUtils.dp2pix(context, INTERVAL_IN_DP);
|
||||
int progressSize = LayoutUtils.dp2pix(context, PROGRESS_SIZE_IN_DP);
|
||||
mPagerLayoutManager = new PagerLayoutManager(context, this, interval, progressSize);
|
||||
mPagerLayoutManager.onAttach(iterator);
|
||||
mLayoutManager = mPagerLayoutManager;
|
||||
mScrollLayoutManager = new ScrollLayoutManager(context, this, interval, progressSize);
|
||||
mScrollLayoutManager.onAttach(iterator);
|
||||
mLayoutManager = mScrollLayoutManager;
|
||||
|
||||
setBackgroundColor(BACKGROUND_COLOR);
|
||||
}
|
||||
@@ -355,6 +360,7 @@ public class GalleryView extends GLView implements GestureRecognizer.Listener {
|
||||
GalleryPageView page = mRecycler.obtain();
|
||||
if (page == null) {
|
||||
page = new GalleryPageView(mContext);
|
||||
page.setMinimumHeight(mPageMinHeight);
|
||||
}
|
||||
return page;
|
||||
}
|
||||
|
||||
@@ -35,6 +35,11 @@ public class GestureRecognizer {
|
||||
boolean onDoubleTap(float x, float y);
|
||||
boolean onDoubleTapConfirmed(float x, float y);
|
||||
boolean onScroll(float dx, float dy, float totalX, float totalY, float x, float y);
|
||||
|
||||
/**
|
||||
* @param velocityX Finger from top to bottom is positive
|
||||
* @param velocityY Finger from left to right is positive
|
||||
*/
|
||||
boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY);
|
||||
boolean onScaleBegin(float focusX, float focusY);
|
||||
boolean onScale(float focusX, float focusY, float scale);
|
||||
|
||||
@@ -57,6 +57,8 @@ public class ImageView extends GLView {
|
||||
public static final int START_POSITION_CENTER = 4;
|
||||
|
||||
private Texture mTexture;
|
||||
private int mTextureWidth;
|
||||
private int mTextureHeight;
|
||||
|
||||
private RectF mDst = new RectF();
|
||||
private RectF mSrcActual = new RectF();
|
||||
@@ -75,13 +77,52 @@ public class ImageView extends GLView {
|
||||
@Override
|
||||
protected int getSuggestedMinimumWidth() {
|
||||
return Math.max(super.getSuggestedMinimumWidth(),
|
||||
mTexture == null ? 0 : mTexture.getWidth());
|
||||
mTexture == null ? 0 : mTextureWidth);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getSuggestedMinimumHeight() {
|
||||
return Math.max(super.getSuggestedMinimumHeight(),
|
||||
mTexture == null ? 0 : mTexture.getHeight());
|
||||
mTexture == null ? 0 : mTextureHeight);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onMeasure(int widthSpec, int heightSpec) {
|
||||
if (mTexture == null) {
|
||||
super.onMeasure(widthSpec, heightSpec);
|
||||
} else {
|
||||
float ratio = (float) mTextureWidth / mTextureHeight;
|
||||
int widthSize = MeasureSpec.getSize(widthSpec);
|
||||
int heightSize = MeasureSpec.getSize(heightSpec);
|
||||
int widthMode = MeasureSpec.getMode(widthSpec);
|
||||
int heightMode = MeasureSpec.getMode(heightSpec);
|
||||
int measureWidth = -1;
|
||||
int measureHeight = -1;
|
||||
|
||||
if (widthMode == MeasureSpec.EXACTLY) {
|
||||
measureWidth = widthSize;
|
||||
if (heightMode == MeasureSpec.EXACTLY) {
|
||||
measureHeight = heightSize;
|
||||
} else {
|
||||
measureHeight = (int) (widthSize / ratio);
|
||||
if (heightMode == MeasureSpec.AT_MOST) {
|
||||
measureHeight = Math.min(measureHeight, heightSize);
|
||||
}
|
||||
}
|
||||
} else if (heightMode == MeasureSpec.EXACTLY) {
|
||||
measureHeight = heightSize;
|
||||
measureWidth = (int) (heightSize * ratio);
|
||||
if (widthMode == MeasureSpec.AT_MOST) {
|
||||
measureWidth = Math.min(measureWidth, widthSize);
|
||||
}
|
||||
}
|
||||
|
||||
if (measureWidth == -1 || measureHeight == -1) {
|
||||
super.onMeasure(widthSpec, heightSpec);
|
||||
} else {
|
||||
setMeasuredSize(measureWidth, measureHeight);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -102,8 +143,8 @@ public class ImageView extends GLView {
|
||||
|
||||
scaleDefault[0] = 1.0f;
|
||||
|
||||
float scaleX = (float) getWidth() / mTexture.getWidth();
|
||||
float scaleY = (float) getHeight() / mTexture.getHeight();
|
||||
float scaleX = (float) getWidth() / mTextureWidth;
|
||||
float scaleY = (float) getHeight() / mTextureHeight;
|
||||
if (scaleX < scaleY) {
|
||||
scaleDefault[1] = scaleX;
|
||||
} else {
|
||||
@@ -117,6 +158,22 @@ public class ImageView extends GLView {
|
||||
|
||||
public void setTexture(Texture texture) {
|
||||
mTexture = texture;
|
||||
|
||||
if (texture != null) {
|
||||
mTextureWidth = texture.getWidth();
|
||||
mTextureHeight = texture.getHeight();
|
||||
// Avoid zero and negative
|
||||
if (mTextureWidth <= 0) {
|
||||
mTextureWidth = 1;
|
||||
}
|
||||
if (mTextureHeight <= 0) {
|
||||
mTextureHeight = 1;
|
||||
}
|
||||
} else {
|
||||
mTextureWidth = 1;
|
||||
mTextureHeight = 1;
|
||||
}
|
||||
|
||||
mScaleOffsetDirty = true;
|
||||
mPositionInRootDirty = true;
|
||||
}
|
||||
@@ -254,15 +311,8 @@ public class ImageView extends GLView {
|
||||
return;
|
||||
}
|
||||
|
||||
int textureWidth = mTexture.getWidth();
|
||||
int textureHeight = mTexture.getHeight();
|
||||
// Avoid zero and negative
|
||||
if (textureWidth <= 0) {
|
||||
textureWidth = 1;
|
||||
}
|
||||
if (textureHeight <= 0) {
|
||||
textureHeight = 1;
|
||||
}
|
||||
int textureWidth = mTextureWidth;
|
||||
int textureHeight = mTextureHeight;
|
||||
|
||||
// Set scale
|
||||
float targetWidth;
|
||||
|
||||
@@ -19,6 +19,7 @@ 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;
|
||||
|
||||
@@ -35,8 +36,6 @@ import java.lang.annotation.RetentionPolicy;
|
||||
|
||||
public class PagerLayoutManager extends GalleryView.LayoutManager {
|
||||
|
||||
private static final String TAG = PagerLayoutManager.class.getSimpleName();
|
||||
|
||||
@IntDef({MODE_LEFT_TO_RIGHT, MODE_RIGHT_TO_LEFT})
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
private @interface Mode {}
|
||||
@@ -62,17 +61,16 @@ public class PagerLayoutManager extends GalleryView.LayoutManager {
|
||||
@Mode
|
||||
private int mMode = MODE_RIGHT_TO_LEFT;
|
||||
private int mOffset;
|
||||
private int mDeltaX;
|
||||
private int mDeltaY;
|
||||
private boolean mCanScrollBetweenPages = false;
|
||||
|
||||
private int mInterval;
|
||||
private int mProgressSpec;
|
||||
|
||||
private int[] mScrollRemain = new int[2];
|
||||
private float[] mScaleDefault = new float[3];
|
||||
|
||||
private boolean mCanScrollBetweenPages = false;
|
||||
|
||||
private int mDeltaX;
|
||||
private int mDeltaY;
|
||||
|
||||
private PageFling mPageFling;
|
||||
private SmoothScroller mSmoothScroller;
|
||||
private SmoothScaler mSmoothScaler;
|
||||
@@ -88,12 +86,36 @@ public class PagerLayoutManager extends GalleryView.LayoutManager {
|
||||
mSmoothScaler = new SmoothScaler();
|
||||
}
|
||||
|
||||
private void resetParameters() {
|
||||
mOffset = 0;
|
||||
mDeltaX = 0;
|
||||
mDeltaY = 0;
|
||||
mCanScrollBetweenPages = false;
|
||||
}
|
||||
|
||||
private void cancelAllAnimations() {
|
||||
mSmoothScroller.cancel();
|
||||
mPageFling.cancel();
|
||||
mSmoothScaler.cancel();
|
||||
}
|
||||
|
||||
public void setMode(@Mode int mode) {
|
||||
// TODO
|
||||
if (mMode == mode) {
|
||||
return;
|
||||
}
|
||||
|
||||
mMode = mode;
|
||||
if (mIterator != null) {
|
||||
|
||||
} else {
|
||||
|
||||
// It is attached, refill
|
||||
// Cancel all animations
|
||||
cancelAllAnimations();
|
||||
// Remove all view
|
||||
removeProgress();
|
||||
removeAllPages();
|
||||
// Reset parameters
|
||||
resetParameters();
|
||||
// Request fill
|
||||
mGalleryView.requestFill();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -101,6 +123,8 @@ public class PagerLayoutManager extends GalleryView.LayoutManager {
|
||||
public void onAttach(GalleryView.PageIterator iterator) {
|
||||
AssertUtils.assertEquals("The PagerLayoutManager is attached", mIterator, null);
|
||||
mIterator = iterator;
|
||||
// Reset parameters
|
||||
resetParameters();
|
||||
}
|
||||
|
||||
private void removeProgress() {
|
||||
@@ -136,6 +160,11 @@ public class PagerLayoutManager extends GalleryView.LayoutManager {
|
||||
public GalleryView.PageIterator onDetach() {
|
||||
AssertUtils.assertNotEquals("The PagerLayoutManager is not attached", mIterator, null);
|
||||
|
||||
// Cancel all animations
|
||||
cancelAllAnimations();
|
||||
|
||||
// Remove all view
|
||||
removeProgress();
|
||||
removeAllPages();
|
||||
|
||||
// Clear iterator
|
||||
@@ -268,19 +297,17 @@ public class PagerLayoutManager extends GalleryView.LayoutManager {
|
||||
mDeltaX = 0;
|
||||
mDeltaY = 0;
|
||||
|
||||
mSmoothScroller.cancel();
|
||||
mPageFling.cancel();
|
||||
mSmoothScaler.cancel();
|
||||
cancelAllAnimations();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUp() {
|
||||
mGalleryView.getEdgeView().onRelease();
|
||||
|
||||
if (mCurrent == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
mGalleryView.getEdgeView().onRelease();
|
||||
|
||||
// Scroll
|
||||
if (mOffset != 0) {
|
||||
int width = mGalleryView.getWidth();
|
||||
@@ -447,6 +474,9 @@ public class PagerLayoutManager extends GalleryView.LayoutManager {
|
||||
mDeltaX += dx;
|
||||
mDeltaY += dy;
|
||||
|
||||
|
||||
Log.d("TAG", "mDeltaX = " + mDeltaX);
|
||||
|
||||
if (mDeltaX < 0) {
|
||||
edgeView.onPull(-mDeltaX, y, GLEdgeView.LEFT);
|
||||
if (!edgeView.isFinished(GLEdgeView.RIGHT)) {
|
||||
@@ -466,7 +496,7 @@ public class PagerLayoutManager extends GalleryView.LayoutManager {
|
||||
edgeView.onRelease(GLEdgeView.BOTTOM);
|
||||
}
|
||||
} else if (mDeltaY > 0) {
|
||||
edgeView.onPull(mDeltaY, y, GLEdgeView.BOTTOM);
|
||||
edgeView.onPull(mDeltaY, x, GLEdgeView.BOTTOM);
|
||||
if (!edgeView.isFinished(GLEdgeView.TOP)) {
|
||||
edgeView.onRelease(GLEdgeView.TOP);
|
||||
}
|
||||
@@ -646,6 +676,10 @@ public class PagerLayoutManager extends GalleryView.LayoutManager {
|
||||
mDy = maxY;
|
||||
}
|
||||
|
||||
if (mDx == 0 && mDy == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
setDuration(Math.max(durationX, durationY));
|
||||
start();
|
||||
mGalleryView.invalidate();
|
||||
|
||||
@@ -16,38 +16,256 @@
|
||||
|
||||
package com.hippo.ehviewer.ui.gl;
|
||||
|
||||
import android.content.Context;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.util.Log;
|
||||
import android.view.MotionEvent;
|
||||
|
||||
import com.hippo.gl.view.GLView;
|
||||
import com.hippo.gl.widget.GLEdgeView;
|
||||
import com.hippo.gl.widget.GLProgressView;
|
||||
import com.hippo.yorozuya.AssertUtils;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedList;
|
||||
|
||||
public class ScrollLayoutManager extends GalleryView.LayoutManager {
|
||||
|
||||
public ScrollLayoutManager(@NonNull GalleryView galleryView) {
|
||||
private static final String TAG = ScrollLayoutManager.class.getSimpleName();
|
||||
|
||||
private static final float RESERVATIONS = 0.5f;
|
||||
|
||||
private GalleryView.PageIterator mIterator;
|
||||
|
||||
private GLProgressView mProgress;
|
||||
private LinkedList<GalleryPageView> mPages = new LinkedList<>();
|
||||
|
||||
private int mOffset;
|
||||
private int mDeltaX;
|
||||
private int mDeltaY;
|
||||
|
||||
private int mInterval;
|
||||
private int mProgressSpec;
|
||||
|
||||
private PageFling mPageFling;
|
||||
|
||||
public ScrollLayoutManager(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);
|
||||
}
|
||||
|
||||
private void resetParameters() {
|
||||
mOffset = 0;
|
||||
mDeltaX = 0;
|
||||
mDeltaY = 0;
|
||||
}
|
||||
|
||||
private void cancelAllAnimations() {
|
||||
mPageFling.cancel();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAttach(GalleryView.PageIterator iterator) {
|
||||
AssertUtils.assertEquals("The PagerLayoutManager is attached", mIterator, null);
|
||||
mIterator = iterator;
|
||||
// Reset parameters
|
||||
resetParameters();
|
||||
}
|
||||
|
||||
private void removeProgress() {
|
||||
if (mProgress != null) {
|
||||
mGalleryView.removeComponent(mProgress);
|
||||
mProgress = null;
|
||||
}
|
||||
}
|
||||
|
||||
private void removePage(@NonNull GalleryPageView page) {
|
||||
mGalleryView.removeComponent(page);
|
||||
mIterator.unbind(page);
|
||||
mGalleryView.releasePage(page);
|
||||
}
|
||||
|
||||
private void removeAllPages() {
|
||||
for (GalleryPageView page : mPages) {
|
||||
removePage(page);
|
||||
}
|
||||
mPages.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public GalleryView.PageIterator onDetach() {
|
||||
return null;
|
||||
AssertUtils.assertNotEquals("The PagerLayoutManager is not attached", mIterator, null);
|
||||
|
||||
// Cancel all animations
|
||||
cancelAllAnimations();
|
||||
|
||||
// Remove all view
|
||||
removeProgress();
|
||||
removeAllPages();
|
||||
|
||||
// Clear iterator
|
||||
GalleryView.PageIterator iterator = mIterator;
|
||||
mIterator = null;
|
||||
|
||||
return iterator;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFill() {
|
||||
public synchronized void onFill() {
|
||||
GalleryView.PageIterator iterator = mIterator;
|
||||
GalleryView galleryView = mGalleryView;
|
||||
AssertUtils.assertNotEquals("The PagerLayoutManager is not attached", iterator, null);
|
||||
|
||||
int width = galleryView.getWidth();
|
||||
int height = galleryView.getHeight();
|
||||
|
||||
if (!iterator.isValid()) {
|
||||
// Remove all pages
|
||||
removeAllPages();
|
||||
|
||||
// Ensure progress
|
||||
if (mProgress == null) {
|
||||
mProgress = galleryView.obtainProgress();
|
||||
galleryView.addComponent(mProgress);
|
||||
}
|
||||
|
||||
// Measure and layout progress
|
||||
mProgress.measure(mProgressSpec, mProgressSpec);
|
||||
int progressWidth = mProgress.getMeasuredWidth();
|
||||
int progressHeight = mProgress.getMeasuredHeight();
|
||||
int progressLeft = width / 2 - progressWidth / 2;
|
||||
int progressTop = height / 2 - progressHeight / 2;
|
||||
mProgress.layout(progressLeft, progressTop, progressLeft + progressWidth, progressTop + progressHeight);
|
||||
} else {
|
||||
// Remove progress
|
||||
removeProgress();
|
||||
|
||||
int minY = (int) (-height * RESERVATIONS);
|
||||
|
||||
// Remove useless top view
|
||||
Iterator<GalleryPageView> pages = mPages.iterator();
|
||||
while (pages.hasNext()) {
|
||||
GalleryPageView page = pages.next();
|
||||
int nextTop = page.bounds().bottom + mInterval;
|
||||
if (nextTop < minY) {
|
||||
removePage(page);
|
||||
pages.remove();
|
||||
// Update offset
|
||||
mOffset = nextTop;
|
||||
if (iterator.hasNext()) {
|
||||
iterator.next();
|
||||
} else {
|
||||
Log.e(TAG, "iterator should has next");
|
||||
}
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Fill missing top
|
||||
int oldOffset = mOffset;
|
||||
int y = oldOffset;
|
||||
int widthSpec = GLView.MeasureSpec.makeMeasureSpec(width, GLView.MeasureSpec.EXACTLY);
|
||||
int heightSpec = GLView.MeasureSpec.makeMeasureSpec(height, GLView.MeasureSpec.UNSPECIFIED);
|
||||
int pageSize = 0;
|
||||
while (y >= minY && iterator.hasPrevious()) {
|
||||
iterator.previous();
|
||||
|
||||
GalleryPageView page = galleryView.obtainPage();
|
||||
iterator.bind(page);
|
||||
galleryView.addComponent(page);
|
||||
mPages.add(0, page);
|
||||
|
||||
// Add interval
|
||||
y -= mInterval;
|
||||
|
||||
// Measure and layout
|
||||
page.measure(widthSpec, heightSpec);
|
||||
page.layout(0, y - page.getMeasuredHeight(), width, y);
|
||||
|
||||
// Update y
|
||||
y -= page.getMeasuredHeight();
|
||||
|
||||
// size increase
|
||||
pageSize++;
|
||||
}
|
||||
mOffset = y;
|
||||
|
||||
// Fill from oldOffset
|
||||
iterator.mark();
|
||||
// Go to oldOffset
|
||||
int maxY = (int) (height * (1 + RESERVATIONS));
|
||||
y = oldOffset;
|
||||
pages = mPages.iterator();
|
||||
for (int i = 0; i < pageSize; i++) {
|
||||
if (iterator.hasNext()) {
|
||||
iterator.next();
|
||||
} else {
|
||||
Log.e(TAG, "iterator should has next");
|
||||
}
|
||||
pages.next();
|
||||
}
|
||||
// Do fill
|
||||
while (true) {
|
||||
GalleryPageView page;
|
||||
if (pages == null || !pages.hasNext()) {
|
||||
pages = null;
|
||||
// New page
|
||||
page = galleryView.obtainPage();
|
||||
iterator.bind(page);
|
||||
galleryView.addComponent(page);
|
||||
mPages.add(page);
|
||||
} else {
|
||||
page = pages.next();
|
||||
}
|
||||
|
||||
// Measure and layout
|
||||
page.measure(widthSpec, heightSpec);
|
||||
page.layout(0, y, width, y + page.getMeasuredHeight());
|
||||
|
||||
// size increase
|
||||
pageSize++;
|
||||
|
||||
// Update y and check out of range
|
||||
y += page.getMeasuredHeight();
|
||||
if (y > maxY) {
|
||||
break;
|
||||
}
|
||||
|
||||
y += mInterval;
|
||||
|
||||
// Check has next
|
||||
if (!iterator.hasNext()) {
|
||||
break;
|
||||
}
|
||||
|
||||
iterator.next();
|
||||
}
|
||||
iterator.reset();
|
||||
|
||||
// Remove useless page
|
||||
while (mPages.size() > pageSize) {
|
||||
GalleryPageView page = mPages.removeLast();
|
||||
removePage(page);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDown() {
|
||||
mDeltaX = 0;
|
||||
mDeltaY = 0;
|
||||
|
||||
cancelAllAnimations();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUp() {
|
||||
|
||||
mGalleryView.getEdgeView().onRelease();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -55,14 +273,196 @@ public 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// True for get top or bottom
|
||||
private boolean scrollInternal(float dx, float dy, boolean fling, float x, float y) {
|
||||
if (mPages.size() == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int height = mGalleryView.getHeight();
|
||||
boolean requestFill = false;
|
||||
int remainY = (int) dy;
|
||||
boolean result = false;
|
||||
|
||||
while (remainY != 0) {
|
||||
if (remainY < 0) { // Try to show top
|
||||
int limit;
|
||||
if (mIterator.hasPrevious()) {
|
||||
limit = (int) (-height * RESERVATIONS);
|
||||
} else {
|
||||
limit = 0;
|
||||
}
|
||||
|
||||
if (mOffset - remainY < limit) {
|
||||
mOffset -= remainY;
|
||||
remainY = 0;
|
||||
requestFill = true;
|
||||
mDeltaX = 0;
|
||||
mDeltaY = 0;
|
||||
} else {
|
||||
if (mIterator.hasPrevious()) {
|
||||
mOffset = limit;
|
||||
remainY = remainY + limit - mOffset;
|
||||
onFill();
|
||||
requestFill = false;
|
||||
mDeltaX = 0;
|
||||
mDeltaY = 0;
|
||||
} else {
|
||||
if (mOffset != limit) {
|
||||
mOffset = limit;
|
||||
requestFill = true;
|
||||
}
|
||||
if (!fling) {
|
||||
overScrollEdge(0, remainY + limit - mOffset, x, y);
|
||||
}
|
||||
remainY = 0;
|
||||
result = true;
|
||||
}
|
||||
}
|
||||
} else { // Try to show bottom
|
||||
boolean hasNext = hasNextPage();
|
||||
int limit;
|
||||
if (hasNext) {
|
||||
limit = (int) (height * (1 + RESERVATIONS));
|
||||
} else {
|
||||
limit = height;
|
||||
}
|
||||
int pageBottom = mPages.getLast().bounds().bottom;
|
||||
// Fix limit for page not fill screen
|
||||
limit = Math.min(pageBottom, limit);
|
||||
|
||||
if (pageBottom - remainY > limit) {
|
||||
mOffset -= remainY;
|
||||
remainY = 0;
|
||||
requestFill = true;
|
||||
mDeltaX = 0;
|
||||
mDeltaY = 0;
|
||||
} else {
|
||||
if (hasNext) {
|
||||
mOffset -= pageBottom - limit;
|
||||
remainY = remainY + limit - pageBottom;
|
||||
onFill();
|
||||
requestFill = false;
|
||||
mDeltaX = 0;
|
||||
mDeltaY = 0;
|
||||
} else {
|
||||
if (mOffset != limit) {
|
||||
mOffset -= pageBottom - limit;
|
||||
requestFill = true;
|
||||
}
|
||||
if (!fling) {
|
||||
overScrollEdge(0, remainY + limit - pageBottom, x, y);
|
||||
}
|
||||
remainY = 0;
|
||||
result = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (requestFill) {
|
||||
mGalleryView.requestFill();
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onScroll(float dx, float dy, float totalX, float totalY, float x, float y) {
|
||||
scrollInternal(dx, dy, false, x, y);
|
||||
}
|
||||
|
||||
private boolean hasNextPage() {
|
||||
boolean hasNext = true;
|
||||
GalleryView.PageIterator iterator = mIterator;
|
||||
iterator.mark();
|
||||
|
||||
for (int i = 0, size = mPages.size(); i < size; i++) {
|
||||
if (iterator.hasNext()) {
|
||||
iterator.next();
|
||||
} else {
|
||||
hasNext = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
iterator.reset();
|
||||
return hasNext;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
|
||||
if (mPages.size() <= 0) {
|
||||
return;
|
||||
}
|
||||
// FIXME Bug here
|
||||
int maxY;
|
||||
if (mIterator.hasPrevious()) {
|
||||
maxY = Integer.MAX_VALUE;
|
||||
} else {
|
||||
maxY = -mOffset;
|
||||
}
|
||||
|
||||
int bottom = mOffset;
|
||||
boolean hasNext = true;
|
||||
GalleryView.PageIterator iterator = mIterator;
|
||||
iterator.mark();
|
||||
for (int i = 0, size = mPages.size(); i < size; i++) {
|
||||
if (i != 0) {
|
||||
bottom += mInterval;
|
||||
}
|
||||
bottom += mPages.get(i).getHeight();
|
||||
if (iterator.hasNext()) {
|
||||
iterator.next();
|
||||
} else {
|
||||
hasNext = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
iterator.reset();
|
||||
|
||||
int minY;
|
||||
if (hasNext) {
|
||||
minY = Integer.MIN_VALUE;
|
||||
} else {
|
||||
minY = mGalleryView.getHeight() - bottom;
|
||||
}
|
||||
|
||||
mPageFling.startFling((int) velocityX, 0, 0,
|
||||
(int) velocityY, minY, maxY);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -77,6 +477,111 @@ public class ScrollLayoutManager extends GalleryView.LayoutManager {
|
||||
|
||||
@Override
|
||||
public boolean onUpdateAnimation(long time) {
|
||||
return false;
|
||||
boolean invalidate = mPageFling.calculate(time);
|
||||
return invalidate;
|
||||
}
|
||||
|
||||
class PageFling extends Fling {
|
||||
|
||||
private int mVelocityX;
|
||||
private int mVelocityY;
|
||||
private int mDx;
|
||||
private int mDy;
|
||||
private int mLastX;
|
||||
private int mLastY;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
if (mDx == 0 && mDy == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
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 (scrollInternal(-offsetX, -offsetY, true, 0, 0)) {
|
||||
cancel();
|
||||
onFinish();
|
||||
}
|
||||
mLastX = x;
|
||||
mLastY = y;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onFinish() {
|
||||
boolean topEdge = !mIterator.hasPrevious() && mOffset >= 0;
|
||||
|
||||
int bottom = mOffset;
|
||||
boolean hasNext = true;
|
||||
GalleryView.PageIterator iterator = mIterator;
|
||||
iterator.mark();
|
||||
for (int i = 0, size = mPages.size(); i < size; i++) {
|
||||
if (i != 0) {
|
||||
bottom += mInterval;
|
||||
}
|
||||
bottom += mPages.get(i).getHeight();
|
||||
if (iterator.hasNext()) {
|
||||
iterator.next();
|
||||
} else {
|
||||
hasNext = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
iterator.reset();
|
||||
boolean bottomEdge = !hasNext && bottom <= mGalleryView.getHeight();
|
||||
|
||||
if (topEdge && bottomEdge) {
|
||||
return;
|
||||
}
|
||||
|
||||
// FIXME Bug here
|
||||
Log.d(TAG, "bottom = " + bottom);
|
||||
Log.d(TAG, "mGalleryView.getHeight() = " + mGalleryView.getHeight());
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -150,7 +150,8 @@ abstract public class Animation {
|
||||
Interpolator i = mInterpolator;
|
||||
onCalculate(i != null ? i.getInterpolation(x) : x);
|
||||
|
||||
if (elapse >= mDuration) {
|
||||
// It is ok to call cancel() in onCalculate()
|
||||
if (mStartTime != NO_ANIMATION && elapse >= mDuration) {
|
||||
mRunnedCount++;
|
||||
if (mRunnedCount >= mRepeatCount && mRepeatCount != INFINITE) {
|
||||
onFinish();
|
||||
|
||||
@@ -1,94 +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.util;
|
||||
|
||||
import android.view.InputDevice;
|
||||
import android.view.InputEvent;
|
||||
import android.view.KeyEvent;
|
||||
import android.view.MotionEvent;
|
||||
|
||||
// From http://developer.android.com/training/game-controllers/controller-input.html#dpad
|
||||
public class Dpad {
|
||||
|
||||
public static final int INVALID = -1;
|
||||
public static final int UP = 0;
|
||||
public static final int LEFT = 1;
|
||||
public static final int RIGHT = 2;
|
||||
public static final int DOWN = 3;
|
||||
public static final int CENTER = 4;
|
||||
|
||||
public static int getDirectionPressed(InputEvent event) {
|
||||
if (!isDpadDevice(event)) {
|
||||
return INVALID;
|
||||
}
|
||||
|
||||
int directionPressed = INVALID;
|
||||
|
||||
// If the input event is a MotionEvent, check its hat axis values.
|
||||
if (event instanceof MotionEvent) {
|
||||
|
||||
// Use the hat axis value to find the D-pad direction
|
||||
MotionEvent motionEvent = (MotionEvent) event;
|
||||
float xaxis = motionEvent.getAxisValue(MotionEvent.AXIS_HAT_X);
|
||||
float yaxis = motionEvent.getAxisValue(MotionEvent.AXIS_HAT_Y);
|
||||
|
||||
// Check if the AXIS_HAT_X value is -1 or 1, and set the D-pad
|
||||
// LEFT and RIGHT direction accordingly.
|
||||
if (Float.compare(xaxis, -1.0f) == 0) {
|
||||
directionPressed = Dpad.LEFT;
|
||||
} else if (Float.compare(xaxis, 1.0f) == 0) {
|
||||
directionPressed = Dpad.RIGHT;
|
||||
}
|
||||
// Check if the AXIS_HAT_Y value is -1 or 1, and set the D-pad
|
||||
// UP and DOWN direction accordingly.
|
||||
else if (Float.compare(yaxis, -1.0f) == 0) {
|
||||
directionPressed = Dpad.UP;
|
||||
} else if (Float.compare(yaxis, 1.0f) == 0) {
|
||||
directionPressed = Dpad.DOWN;
|
||||
}
|
||||
}
|
||||
|
||||
// If the input event is a KeyEvent, check its key code.
|
||||
else if (event instanceof KeyEvent) {
|
||||
|
||||
// Use the key code to find the D-pad direction.
|
||||
KeyEvent keyEvent = (KeyEvent) event;
|
||||
if (keyEvent.getKeyCode() == KeyEvent.KEYCODE_DPAD_LEFT) {
|
||||
directionPressed = Dpad.LEFT;
|
||||
} else if (keyEvent.getKeyCode() == KeyEvent.KEYCODE_DPAD_RIGHT) {
|
||||
directionPressed = Dpad.RIGHT;
|
||||
} else if (keyEvent.getKeyCode() == KeyEvent.KEYCODE_DPAD_UP) {
|
||||
directionPressed = Dpad.UP;
|
||||
} else if (keyEvent.getKeyCode() == KeyEvent.KEYCODE_DPAD_DOWN) {
|
||||
directionPressed = Dpad.DOWN;
|
||||
} else if (keyEvent.getKeyCode() == KeyEvent.KEYCODE_DPAD_CENTER) {
|
||||
directionPressed = Dpad.CENTER;
|
||||
}
|
||||
}
|
||||
return directionPressed;
|
||||
}
|
||||
|
||||
public static boolean isDpadDevice(InputEvent event) {
|
||||
// Check that input comes from a device with directional pads.
|
||||
if ((event.getSource() & InputDevice.SOURCE_DPAD)
|
||||
!= InputDevice.SOURCE_DPAD) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -48,7 +48,8 @@ public class PermissionRequester {
|
||||
new String[]{permission},
|
||||
requestCode);
|
||||
}
|
||||
}).setNegativeButton(android.R.string.cancel, null);
|
||||
}).setNegativeButton(android.R.string.cancel, null)
|
||||
.show();
|
||||
} else {
|
||||
ActivityCompat.requestPermissions(activity,
|
||||
new String[]{permission},
|
||||
|
||||
Reference in new issue
Block a user