Add ScrollLayoutManager

This commit is contained in:
seven332 committed 2016-02-12 23:32:02 +08:00
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},