add zoom support
This commit is contained in:
parent
ee77f0f8fb
commit
a8c289a4d9
|
|
@ -7,7 +7,9 @@ import android.app.ProgressDialog;
|
|||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.RectF;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Matrix;
|
||||
import android.graphics.Paint;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.support.annotation.NonNull;
|
||||
|
|
@ -47,6 +49,8 @@ import net.sf.andpdf.refs.HardReference;
|
|||
import java.io.IOException;
|
||||
import java.util.Locale;
|
||||
|
||||
import uk.co.senab.photoview.PhotoViewAttacher;
|
||||
|
||||
import static android.content.Context.INPUT_METHOD_SERVICE;
|
||||
|
||||
/**
|
||||
|
|
@ -111,7 +115,7 @@ public class PdfViewerFragment extends Fragment {
|
|||
mGraphView = new GraphView(getActivity());
|
||||
mGraphView.mBi = mOldGraphView.mBi;
|
||||
mOldGraphView = null;
|
||||
mGraphView.pdfView.setImageBitmap(mGraphView.mBi);
|
||||
mGraphView.pdfZoomedImageView.setImageBitmap(mGraphView.mBi);
|
||||
mGraphView.updateTexts();
|
||||
return mGraphView;
|
||||
} else {
|
||||
|
|
@ -437,7 +441,8 @@ public class PdfViewerFragment extends Fragment {
|
|||
|
||||
private class GraphView extends FullScrollView {
|
||||
public Bitmap mBi;
|
||||
public ImageView pdfView;
|
||||
public ImageView pdfZoomedImageView;
|
||||
public PhotoViewAttacher photoViewAttacher;
|
||||
public Button mBtPage;
|
||||
private Button mBtPage2;
|
||||
|
||||
|
|
@ -459,7 +464,8 @@ public class PdfViewerFragment extends Fragment {
|
|||
// remember page button for updates
|
||||
mBtPage2 = mBtPage;
|
||||
|
||||
pdfView = new ImageView(context);
|
||||
pdfZoomedImageView = new ImageView(context);
|
||||
photoViewAttacher = new PhotoViewAttacher(pdfZoomedImageView);
|
||||
setPageBitmap(null);
|
||||
updateImage();
|
||||
|
||||
|
|
@ -470,7 +476,7 @@ public class PdfViewerFragment extends Fragment {
|
|||
// setHorizontalFadingEdgeEnabled(true);
|
||||
// setVerticalScrollBarEnabled(true);
|
||||
// setVerticalFadingEdgeEnabled(true);
|
||||
addView(pdfView);
|
||||
addView(pdfZoomedImageView);
|
||||
}
|
||||
|
||||
private void addNavButtons(ViewGroup vg) {
|
||||
|
|
@ -559,7 +565,8 @@ public class PdfViewerFragment extends Fragment {
|
|||
private void updateImage() {
|
||||
uiHandler.post(new Runnable() {
|
||||
public void run() {
|
||||
pdfView.setImageBitmap(mBi);
|
||||
pdfZoomedImageView.setImageBitmap(mBi);
|
||||
photoViewAttacher.update();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
@ -601,11 +608,9 @@ public class PdfViewerFragment extends Fragment {
|
|||
mPdfPage = mPdfFile.getPage(page, true);
|
||||
}
|
||||
|
||||
float width = mPdfPage.getWidth();
|
||||
float height = mPdfPage.getHeight();
|
||||
RectF clip = null;
|
||||
Bitmap bi = mPdfPage.getImage((int) (width * (mGraphView.getWidth() / width)), (int) (height * (mGraphView.getHeight() / height)), clip, true, true);
|
||||
mGraphView.setPageBitmap(bi);
|
||||
final Bitmap bitmap = mPdfPage.getImage(mGraphView.getWidth() * 2, mGraphView.getHeight() * 2, null, true, true);
|
||||
final Bitmap bitmapWithoutQualityLose = getBitmapWithoutQualityLose(bitmap, mGraphView.getWidth(), mGraphView.getHeight());
|
||||
mGraphView.setPageBitmap(bitmapWithoutQualityLose);
|
||||
mGraphView.updateImage();
|
||||
} catch (Throwable e) {
|
||||
Log.e(TAG, e.getMessage(), e);
|
||||
|
|
@ -613,6 +618,26 @@ public class PdfViewerFragment extends Fragment {
|
|||
hideProgressBar();
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public Bitmap getBitmapWithoutQualityLose(@NonNull final Bitmap bitmap, int newWidth, int newHeight) {
|
||||
final Bitmap scaledBitmap = Bitmap.createBitmap(newWidth, newHeight, Bitmap.Config.ARGB_8888);
|
||||
|
||||
float ratioX = newWidth / (float) bitmap.getWidth();
|
||||
float ratioY = newHeight / (float) bitmap.getHeight();
|
||||
float middleX = newWidth / 2.0f;
|
||||
float middleY = newHeight / 2.0f;
|
||||
|
||||
final Matrix scaleMatrix = new Matrix();
|
||||
scaleMatrix.setScale(ratioX, ratioY, middleX, middleY);
|
||||
|
||||
final Canvas canvas = new Canvas(scaledBitmap);
|
||||
canvas.setMatrix(scaleMatrix);
|
||||
canvas.drawBitmap(bitmap, middleX - bitmap.getWidth() / 2, middleY - bitmap.getHeight() / 2, new Paint(Paint.FILTER_BITMAP_FLAG));
|
||||
|
||||
return scaledBitmap;
|
||||
|
||||
}
|
||||
|
||||
private void hideProgressBar() {
|
||||
if (progress != null) {
|
||||
progress.dismiss();
|
||||
|
|
@ -648,6 +673,10 @@ public class PdfViewerFragment extends Fragment {
|
|||
public void onDestroy() {
|
||||
super.onDestroy();
|
||||
byteArray = null;
|
||||
if (mGraphView != null) {
|
||||
mGraphView.mBi = null;
|
||||
mGraphView.photoViewAttacher.cleanup();
|
||||
}
|
||||
}
|
||||
|
||||
private int getPreviousPageImageResource() {
|
||||
|
|
|
|||
|
|
@ -1,18 +0,0 @@
|
|||
apply plugin: 'com.android.library'
|
||||
android {
|
||||
compileSdkVersion 23
|
||||
buildToolsVersion '23.0.2'
|
||||
|
||||
defaultConfig {
|
||||
minSdkVersion 7
|
||||
targetSdkVersion 7
|
||||
}
|
||||
|
||||
buildTypes {
|
||||
release {
|
||||
minifyEnabled false
|
||||
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt'
|
||||
}
|
||||
}
|
||||
}
|
||||
dependencies {}
|
||||
|
|
@ -1,9 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="com.polites.android"
|
||||
android:versionCode="1"
|
||||
android:versionName="1.0" >
|
||||
|
||||
<uses-sdk android:minSdkVersion="7" />
|
||||
|
||||
</manifest>
|
||||
|
|
@ -1,32 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2012 Jason Polites
|
||||
*
|
||||
* 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.polites.android;
|
||||
|
||||
/**
|
||||
* @author Jason Polites
|
||||
*
|
||||
*/
|
||||
public interface Animation {
|
||||
|
||||
/**
|
||||
* Transforms the view.
|
||||
* @param view
|
||||
* @param diffTime
|
||||
* @return true if this animation should remain active. False otherwise.
|
||||
*/
|
||||
public boolean update(GestureImageView view, long time);
|
||||
|
||||
}
|
||||
|
|
@ -1,96 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2012 Jason Polites
|
||||
*
|
||||
* 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.polites.android;
|
||||
|
||||
|
||||
/**
|
||||
* @author Jason Polites
|
||||
*
|
||||
*/
|
||||
public class Animator extends Thread {
|
||||
|
||||
private GestureImageView view;
|
||||
private Animation animation;
|
||||
private boolean running = false;
|
||||
private boolean active = false;
|
||||
private long lastTime = -1L;
|
||||
|
||||
public Animator(GestureImageView view, String threadName) {
|
||||
super(threadName);
|
||||
this.view = view;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
|
||||
running = true;
|
||||
|
||||
while(running) {
|
||||
|
||||
while(active && animation != null) {
|
||||
long time = System.currentTimeMillis();
|
||||
active = animation.update(view, time - lastTime);
|
||||
view.redraw();
|
||||
lastTime = time;
|
||||
|
||||
while(active) {
|
||||
try {
|
||||
if(view.waitForDraw(32)) { // 30Htz
|
||||
break;
|
||||
}
|
||||
}
|
||||
catch (InterruptedException ignore) {
|
||||
active = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
synchronized(this) {
|
||||
if(running) {
|
||||
try {
|
||||
wait();
|
||||
}
|
||||
catch (InterruptedException ignore) {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized void finish() {
|
||||
running = false;
|
||||
active = false;
|
||||
notifyAll();
|
||||
}
|
||||
|
||||
public void play(Animation transformer) {
|
||||
if(active) {
|
||||
cancel();
|
||||
}
|
||||
this.animation = transformer;
|
||||
|
||||
activate();
|
||||
}
|
||||
|
||||
public synchronized void activate() {
|
||||
lastTime = System.currentTimeMillis();
|
||||
active = true;
|
||||
notifyAll();
|
||||
}
|
||||
|
||||
public void cancel() {
|
||||
active = false;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,12 +0,0 @@
|
|||
package com.polites.android;
|
||||
|
||||
/**
|
||||
* @author winney E-mail: weiyixiong@tigerbrokers.com
|
||||
* @version 创建时间: 2015/11/18 下午4:49
|
||||
*/
|
||||
public class Direction {
|
||||
public final static int LEFT = 1;
|
||||
public final static int TOP = 2;
|
||||
public final static int RIGHT = 3;
|
||||
public final static int BOTTOM = 4;
|
||||
}
|
||||
|
|
@ -1,74 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2012 Jason Polites
|
||||
*
|
||||
* 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.polites.android;
|
||||
|
||||
/**
|
||||
* @author Jason Polites
|
||||
*
|
||||
*/
|
||||
public class FlingAnimation implements Animation {
|
||||
|
||||
private float velocityX;
|
||||
private float velocityY;
|
||||
|
||||
private float factor = 0.95f;
|
||||
|
||||
private float threshold = 10;
|
||||
|
||||
private FlingAnimationListener listener;
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see com.polites.android.Transformer#update(com.polites.android.GestureImageView, long)
|
||||
*/
|
||||
@Override
|
||||
public boolean update(GestureImageView view, long time) {
|
||||
float seconds = (float) time / 1000.0f;
|
||||
|
||||
float dx = velocityX * seconds;
|
||||
float dy = velocityY * seconds;
|
||||
|
||||
velocityX *= factor;
|
||||
velocityY *= factor;
|
||||
|
||||
boolean active = (Math.abs(velocityX) > threshold && Math.abs(velocityY) > threshold);
|
||||
|
||||
if(listener != null) {
|
||||
listener.onMove(dx, dy);
|
||||
|
||||
if(!active) {
|
||||
listener.onComplete();
|
||||
}
|
||||
}
|
||||
|
||||
return active;
|
||||
}
|
||||
|
||||
public void setVelocityX(float velocityX) {
|
||||
this.velocityX = velocityX;
|
||||
}
|
||||
|
||||
public void setVelocityY(float velocityY) {
|
||||
this.velocityY = velocityY;
|
||||
}
|
||||
|
||||
public void setFactor(float factor) {
|
||||
this.factor = factor;
|
||||
}
|
||||
|
||||
public void setListener(FlingAnimationListener listener) {
|
||||
this.listener = listener;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,29 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2012 Jason Polites
|
||||
*
|
||||
* 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.polites.android;
|
||||
|
||||
|
||||
/**
|
||||
* @author Jason Polites
|
||||
*
|
||||
*/
|
||||
public interface FlingAnimationListener {
|
||||
|
||||
public void onMove(float x, float y);
|
||||
|
||||
public void onComplete();
|
||||
|
||||
}
|
||||
|
|
@ -1,45 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2012 Jason Polites
|
||||
*
|
||||
* 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.polites.android;
|
||||
|
||||
import android.view.GestureDetector.SimpleOnGestureListener;
|
||||
import android.view.MotionEvent;
|
||||
|
||||
|
||||
/**
|
||||
* @author Jason Polites
|
||||
*
|
||||
*/
|
||||
public class FlingListener extends SimpleOnGestureListener {
|
||||
|
||||
private float velocityX;
|
||||
private float velocityY;
|
||||
|
||||
@Override
|
||||
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
|
||||
this.velocityX = velocityX;
|
||||
this.velocityY = velocityY;
|
||||
return true;
|
||||
}
|
||||
|
||||
public float getVelocityX() {
|
||||
return velocityX;
|
||||
}
|
||||
|
||||
public float getVelocityY() {
|
||||
return velocityY;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,698 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2012 Jason Polites
|
||||
*
|
||||
* 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.polites.android;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.Configuration;
|
||||
import android.database.Cursor;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.BitmapFactory;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.ColorFilter;
|
||||
import android.graphics.Matrix;
|
||||
import android.graphics.drawable.BitmapDrawable;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.net.Uri;
|
||||
import android.provider.MediaStore;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.Log;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup.LayoutParams;
|
||||
import android.widget.ImageView;
|
||||
import java.io.InputStream;
|
||||
import java.util.concurrent.Semaphore;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public class GestureImageView extends ImageView {
|
||||
|
||||
public static final String GLOBAL_NS = "http://schemas.android.com/apk/res/android";
|
||||
public static final String LOCAL_NS = "http://schemas.polites.com/android";
|
||||
|
||||
private final Semaphore drawLock = new Semaphore(0);
|
||||
private Animator animator;
|
||||
|
||||
private Drawable drawable;
|
||||
private int drawableWidth = 0;
|
||||
private int drawableHeight = 0;
|
||||
|
||||
private float x = 0, y = 0;
|
||||
|
||||
private float scaleAdjust = 1.0f;
|
||||
private float startingScale = -1.0f;
|
||||
|
||||
private float scale = 1.0f;
|
||||
private float maxScale = 5.0f;
|
||||
private float minScale = 0.75f;
|
||||
private float fitScaleHorizontal = 1.0f;
|
||||
private float fitScaleVertical = 1.0f;
|
||||
private float rotation = 0.0f;
|
||||
|
||||
private float centerX;
|
||||
private float centerY;
|
||||
|
||||
private Float startX, startY;
|
||||
|
||||
private int hWidth;
|
||||
private int hHeight;
|
||||
|
||||
private int resId = -1;
|
||||
private boolean recycle = false;
|
||||
private boolean strict = false;
|
||||
|
||||
private int displayHeight;
|
||||
private int displayWidth;
|
||||
|
||||
private int alpha = 255;
|
||||
private ColorFilter colorFilter;
|
||||
|
||||
private int deviceOrientation = -1;
|
||||
private int imageOrientation;
|
||||
|
||||
private GestureImageViewListener gestureImageViewListener;
|
||||
private GestureImageViewTouchListener gestureImageViewTouchListener;
|
||||
private GestureImageViewTouchListener.OnReachBoundListener onReachBoundListener;
|
||||
|
||||
private OnTouchListener customOnTouchListener;
|
||||
private OnClickListener onClickListener;
|
||||
|
||||
public GestureImageView(Context context, AttributeSet attrs, int defStyle) {
|
||||
this(context, attrs);
|
||||
}
|
||||
|
||||
public GestureImageView(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
|
||||
String scaleType = attrs.getAttributeValue(GLOBAL_NS, "scaleType");
|
||||
|
||||
if (scaleType == null || scaleType.trim().length() == 0) {
|
||||
setScaleType(ScaleType.CENTER_INSIDE);
|
||||
}
|
||||
|
||||
String strStartX = attrs.getAttributeValue(LOCAL_NS, "start-x");
|
||||
String strStartY = attrs.getAttributeValue(LOCAL_NS, "start-y");
|
||||
|
||||
if (strStartX != null && strStartX.trim().length() > 0) {
|
||||
startX = Float.parseFloat(strStartX);
|
||||
}
|
||||
|
||||
if (strStartY != null && strStartY.trim().length() > 0) {
|
||||
startY = Float.parseFloat(strStartY);
|
||||
}
|
||||
|
||||
setStartingScale(attrs.getAttributeFloatValue(LOCAL_NS, "start-scale", startingScale));
|
||||
setMinScale(attrs.getAttributeFloatValue(LOCAL_NS, "min-scale", minScale));
|
||||
setMaxScale(attrs.getAttributeFloatValue(LOCAL_NS, "max-scale", maxScale));
|
||||
setStrict(attrs.getAttributeBooleanValue(LOCAL_NS, "strict", strict));
|
||||
setRecycle(attrs.getAttributeBooleanValue(LOCAL_NS, "recycle", recycle));
|
||||
|
||||
initImage();
|
||||
}
|
||||
|
||||
public GestureImageView(Context context) {
|
||||
super(context);
|
||||
setScaleType(ScaleType.CENTER_INSIDE);
|
||||
initImage();
|
||||
}
|
||||
|
||||
@Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
|
||||
if (drawable != null) {
|
||||
int orientation = getResources().getConfiguration().orientation;
|
||||
if (orientation == Configuration.ORIENTATION_LANDSCAPE) {
|
||||
displayHeight = MeasureSpec.getSize(heightMeasureSpec);
|
||||
|
||||
if (getLayoutParams().width == LayoutParams.WRAP_CONTENT) {
|
||||
float ratio = (float) getImageWidth() / (float) getImageHeight();
|
||||
displayWidth = Math.round((float) displayHeight * ratio);
|
||||
} else {
|
||||
displayWidth = MeasureSpec.getSize(widthMeasureSpec);
|
||||
}
|
||||
} else {
|
||||
displayWidth = MeasureSpec.getSize(widthMeasureSpec);
|
||||
|
||||
if (getLayoutParams().height == LayoutParams.WRAP_CONTENT) {
|
||||
float ratio = (float) getImageHeight() / (float) getImageWidth();
|
||||
displayHeight = Math.round((float) displayWidth * ratio);
|
||||
} else {
|
||||
displayHeight = MeasureSpec.getSize(heightMeasureSpec);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
displayHeight = MeasureSpec.getSize(heightMeasureSpec);
|
||||
displayWidth = MeasureSpec.getSize(widthMeasureSpec);
|
||||
}
|
||||
if (displayWidth == 0 && getImageWidth() != 0) {
|
||||
displayWidth = getImageWidth();
|
||||
}
|
||||
if (displayHeight == 0 && getImageHeight() != 0) {
|
||||
displayHeight = getImageHeight();
|
||||
}
|
||||
|
||||
setMeasuredDimension(displayWidth, displayHeight);
|
||||
}
|
||||
|
||||
@Override protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
|
||||
super.onLayout(changed, left, top, right, bottom);
|
||||
setupCanvas(displayWidth, displayHeight, getResources().getConfiguration().orientation);
|
||||
}
|
||||
|
||||
protected void setupCanvas(int measuredWidth, int measuredHeight, int orientation) {
|
||||
|
||||
if (deviceOrientation != orientation) {
|
||||
deviceOrientation = orientation;
|
||||
}
|
||||
|
||||
if (drawable != null) {
|
||||
int imageWidth = getImageWidth();
|
||||
int imageHeight = getImageHeight();
|
||||
|
||||
hWidth = Math.round(((float) imageWidth / 2.0f));
|
||||
hHeight = Math.round(((float) imageHeight / 2.0f));
|
||||
|
||||
measuredWidth -= (getPaddingLeft() + getPaddingRight());
|
||||
measuredHeight -= (getPaddingTop() + getPaddingBottom());
|
||||
|
||||
computeCropScale(imageWidth, imageHeight, measuredWidth, measuredHeight);
|
||||
|
||||
if (startingScale <= 0.0f) {
|
||||
computeStartingScale(imageWidth, imageHeight, measuredWidth, measuredHeight);
|
||||
}
|
||||
|
||||
scaleAdjust = startingScale;
|
||||
|
||||
this.centerX = (float) measuredWidth / 2.0f;
|
||||
this.centerY = (float) measuredHeight / 2.0f;
|
||||
|
||||
if (startX == null) {
|
||||
x = centerX;
|
||||
} else {
|
||||
x = startX;
|
||||
}
|
||||
|
||||
if (startY == null) {
|
||||
y = centerY;
|
||||
} else {
|
||||
y = startY;
|
||||
}
|
||||
|
||||
gestureImageViewTouchListener = new GestureImageViewTouchListener(this, measuredWidth, measuredHeight);
|
||||
gestureImageViewTouchListener.setOnReachBoundListener(onReachBoundListener);
|
||||
|
||||
if (isLandscape()) {
|
||||
gestureImageViewTouchListener.setMinScale(minScale * fitScaleHorizontal);
|
||||
} else {
|
||||
gestureImageViewTouchListener.setMinScale(minScale * fitScaleVertical);
|
||||
}
|
||||
|
||||
gestureImageViewTouchListener.setMaxScale(maxScale * startingScale);
|
||||
|
||||
gestureImageViewTouchListener.setFitScaleHorizontal(fitScaleHorizontal);
|
||||
gestureImageViewTouchListener.setFitScaleVertical(fitScaleVertical);
|
||||
gestureImageViewTouchListener.setCanvasWidth(measuredWidth);
|
||||
gestureImageViewTouchListener.setCanvasHeight(measuredHeight);
|
||||
gestureImageViewTouchListener.setOnClickListener(onClickListener);
|
||||
|
||||
drawable.setBounds(-hWidth, -hHeight, hWidth, hHeight);
|
||||
|
||||
super.setOnTouchListener(new OnTouchListener() {
|
||||
@Override public boolean onTouch(View v, MotionEvent event) {
|
||||
if (customOnTouchListener != null) {
|
||||
customOnTouchListener.onTouch(v, event);
|
||||
}
|
||||
return gestureImageViewTouchListener.onTouch(v, event);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
protected void computeCropScale(int imageWidth, int imageHeight, int measuredWidth, int measuredHeight) {
|
||||
fitScaleHorizontal = (float) measuredWidth / (float) imageWidth;
|
||||
fitScaleVertical = (float) measuredHeight / (float) imageHeight;
|
||||
}
|
||||
|
||||
protected void computeStartingScale(int imageWidth, int imageHeight, int measuredWidth, int measuredHeight) {
|
||||
switch (getScaleType()) {
|
||||
case CENTER:
|
||||
// Center the image in the view, but perform no scaling.
|
||||
startingScale = 1.0f;
|
||||
break;
|
||||
|
||||
case CENTER_CROP:
|
||||
// Scale the image uniformly (maintain the image's aspect ratio) so that both dimensions
|
||||
// (width and height) of the image will be equal to or larger than the corresponding dimension of the view (minus padding).
|
||||
startingScale =
|
||||
Math.max((float) measuredHeight / (float) imageHeight, (float) measuredWidth / (float) imageWidth);
|
||||
break;
|
||||
|
||||
case CENTER_INSIDE:
|
||||
|
||||
// Scale the image uniformly (maintain the image's aspect ratio) so that both dimensions
|
||||
// (width and height) of the image will be equal to or less than the corresponding dimension of the view (minus padding).
|
||||
float wRatio = (float) imageWidth / (float) measuredWidth;
|
||||
float hRatio = (float) imageHeight / (float) measuredHeight;
|
||||
|
||||
if (wRatio > hRatio) {
|
||||
startingScale = fitScaleHorizontal;
|
||||
} else {
|
||||
startingScale = fitScaleVertical;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
protected boolean isRecycled() {
|
||||
if (drawable != null && drawable instanceof BitmapDrawable) {
|
||||
Bitmap bitmap = ((BitmapDrawable) drawable).getBitmap();
|
||||
if (bitmap != null) {
|
||||
return bitmap.isRecycled();
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
protected void recycle() {
|
||||
if (recycle && drawable != null && drawable instanceof BitmapDrawable) {
|
||||
Bitmap bitmap = ((BitmapDrawable) drawable).getBitmap();
|
||||
if (bitmap != null) {
|
||||
bitmap.recycle();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override protected void onDraw(Canvas canvas) {
|
||||
if (true) {
|
||||
if (drawable != null && !isRecycled()) {
|
||||
if (drawableHeight == 0 && drawableWidth == 0) {
|
||||
return;
|
||||
}
|
||||
canvas.save();
|
||||
|
||||
float adjustedScale = scale * scaleAdjust;
|
||||
|
||||
canvas.translate(x, y);
|
||||
|
||||
if (rotation != 0.0f) {
|
||||
canvas.rotate(rotation);
|
||||
}
|
||||
|
||||
if (adjustedScale != 1.0f) {
|
||||
canvas.scale(adjustedScale, adjustedScale);
|
||||
}
|
||||
//drawable.setBounds(0, 0, drawableWidth, drawableHeight);
|
||||
drawable.draw(canvas);
|
||||
|
||||
canvas.restore();
|
||||
}
|
||||
|
||||
if (drawLock.availablePermits() <= 0) {
|
||||
drawLock.release();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Waits for a draw
|
||||
*
|
||||
* @param max time to wait for draw (ms)
|
||||
* @throws InterruptedException
|
||||
*/
|
||||
public boolean waitForDraw(long timeout) throws InterruptedException {
|
||||
return drawLock.tryAcquire(timeout, TimeUnit.MILLISECONDS);
|
||||
}
|
||||
|
||||
@Override protected void onAttachedToWindow() {
|
||||
animator = new Animator(this, "GestureImageViewAnimator");
|
||||
animator.start();
|
||||
|
||||
if (resId >= 0 && drawable == null) {
|
||||
setImageResource(resId);
|
||||
}
|
||||
|
||||
super.onAttachedToWindow();
|
||||
}
|
||||
|
||||
public void animationStart(Animation animation) {
|
||||
if (animator != null) {
|
||||
animator.play(animation);
|
||||
}
|
||||
}
|
||||
|
||||
public void animationStop() {
|
||||
if (animator != null) {
|
||||
animator.cancel();
|
||||
}
|
||||
}
|
||||
|
||||
@Override protected void onDetachedFromWindow() {
|
||||
if (animator != null) {
|
||||
animator.finish();
|
||||
}
|
||||
if (recycle && drawable != null && !isRecycled()) {
|
||||
recycle();
|
||||
drawable = null;
|
||||
}
|
||||
super.onDetachedFromWindow();
|
||||
}
|
||||
|
||||
protected void initImage() {
|
||||
if (this.drawable != null) {
|
||||
drawableWidth = drawable.getIntrinsicWidth();
|
||||
drawableHeight = drawable.getIntrinsicHeight();
|
||||
this.drawable.setAlpha(alpha);
|
||||
this.drawable.setFilterBitmap(true);
|
||||
if (colorFilter != null) {
|
||||
this.drawable.setColorFilter(colorFilter);
|
||||
}
|
||||
}
|
||||
|
||||
requestLayout();
|
||||
redraw();
|
||||
}
|
||||
|
||||
public void setImageBitmap(Bitmap image) {
|
||||
this.drawable = new BitmapDrawable(getResources(), image);
|
||||
initImage();
|
||||
}
|
||||
|
||||
@Override public void setImageDrawable(Drawable drawable) {
|
||||
this.drawable = drawable;
|
||||
initImage();
|
||||
}
|
||||
|
||||
public void setImageResource(int id) {
|
||||
if (this.drawable != null) {
|
||||
this.recycle();
|
||||
}
|
||||
if (id >= 0) {
|
||||
this.resId = id;
|
||||
setImageDrawable(getContext().getResources().getDrawable(id));
|
||||
}
|
||||
}
|
||||
|
||||
public int getScaledWidth() {
|
||||
return Math.round(getImageWidth() * getScale());
|
||||
}
|
||||
|
||||
public int getScaledHeight() {
|
||||
return Math.round(getImageHeight() * getScale());
|
||||
}
|
||||
|
||||
public int getImageWidth() {
|
||||
if (drawable != null) {
|
||||
return drawable.getIntrinsicWidth();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
public int getImageHeight() {
|
||||
if (drawable != null) {
|
||||
return drawable.getIntrinsicHeight();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
public void moveBy(float x, float y) {
|
||||
this.x += x;
|
||||
this.y += y;
|
||||
}
|
||||
|
||||
public void setPosition(float x, float y) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
}
|
||||
|
||||
public void redraw() {
|
||||
postInvalidate();
|
||||
}
|
||||
|
||||
public void setMinScale(float min) {
|
||||
this.minScale = min;
|
||||
if (gestureImageViewTouchListener != null) {
|
||||
gestureImageViewTouchListener.setMinScale(min * fitScaleHorizontal);
|
||||
}
|
||||
}
|
||||
|
||||
public void setMaxScale(float max) {
|
||||
this.maxScale = max;
|
||||
if (gestureImageViewTouchListener != null) {
|
||||
gestureImageViewTouchListener.setMaxScale(max * startingScale);
|
||||
}
|
||||
}
|
||||
|
||||
public void setScale(float scale) {
|
||||
scaleAdjust = scale;
|
||||
}
|
||||
|
||||
public float getScale() {
|
||||
return scaleAdjust;
|
||||
}
|
||||
|
||||
public float getImageX() {
|
||||
return x;
|
||||
}
|
||||
|
||||
public float getImageY() {
|
||||
return y;
|
||||
}
|
||||
|
||||
public boolean isStrict() {
|
||||
return strict;
|
||||
}
|
||||
|
||||
public void setStrict(boolean strict) {
|
||||
this.strict = strict;
|
||||
}
|
||||
|
||||
public boolean isRecycle() {
|
||||
return recycle;
|
||||
}
|
||||
|
||||
public void setRecycle(boolean recycle) {
|
||||
this.recycle = recycle;
|
||||
}
|
||||
|
||||
public void reset() {
|
||||
x = centerX;
|
||||
y = centerY;
|
||||
scaleAdjust = startingScale;
|
||||
if (gestureImageViewTouchListener != null) {
|
||||
gestureImageViewTouchListener.reset();
|
||||
}
|
||||
redraw();
|
||||
}
|
||||
|
||||
public void setRotation(float rotation) {
|
||||
this.rotation = rotation;
|
||||
}
|
||||
|
||||
public void setGestureImageViewListener(GestureImageViewListener pinchImageViewListener) {
|
||||
this.gestureImageViewListener = pinchImageViewListener;
|
||||
}
|
||||
|
||||
public GestureImageViewListener getGestureImageViewListener() {
|
||||
return gestureImageViewListener;
|
||||
}
|
||||
|
||||
@Override public Drawable getDrawable() {
|
||||
return drawable;
|
||||
}
|
||||
|
||||
@Override public void setAlpha(int alpha) {
|
||||
this.alpha = alpha;
|
||||
if (drawable != null) {
|
||||
drawable.setAlpha(alpha);
|
||||
}
|
||||
}
|
||||
|
||||
@Override public void setColorFilter(ColorFilter cf) {
|
||||
this.colorFilter = cf;
|
||||
if (drawable != null) {
|
||||
drawable.setColorFilter(cf);
|
||||
}
|
||||
}
|
||||
|
||||
@Override public void setImageURI(Uri mUri) {
|
||||
if ("content".equals(mUri.getScheme())) {
|
||||
try {
|
||||
String[] orientationColumn = { MediaStore.Images.Media.ORIENTATION };
|
||||
|
||||
Cursor cur = getContext().getContentResolver().query(mUri, orientationColumn, null, null, null);
|
||||
|
||||
if (cur != null && cur.moveToFirst()) {
|
||||
imageOrientation = cur.getInt(cur.getColumnIndex(orientationColumn[0]));
|
||||
}
|
||||
|
||||
InputStream in = null;
|
||||
|
||||
try {
|
||||
in = getContext().getContentResolver().openInputStream(mUri);
|
||||
Bitmap bmp = BitmapFactory.decodeStream(in);
|
||||
|
||||
if (imageOrientation != 0) {
|
||||
Matrix m = new Matrix();
|
||||
m.postRotate(imageOrientation);
|
||||
Bitmap rotated = Bitmap.createBitmap(bmp, 0, 0, bmp.getWidth(), bmp.getHeight(), m, true);
|
||||
bmp.recycle();
|
||||
setImageDrawable(new BitmapDrawable(getResources(), rotated));
|
||||
} else {
|
||||
setImageDrawable(new BitmapDrawable(getResources(), bmp));
|
||||
}
|
||||
} finally {
|
||||
if (in != null) {
|
||||
in.close();
|
||||
}
|
||||
|
||||
if (cur != null) {
|
||||
cur.close();
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Log.w("GestureImageView", "Unable to open content: " + mUri, e);
|
||||
}
|
||||
} else {
|
||||
setImageDrawable(Drawable.createFromPath(mUri.toString()));
|
||||
}
|
||||
|
||||
if (drawable == null) {
|
||||
Log.e("GestureImageView", "resolveUri failed on bad bitmap uri: " + mUri);
|
||||
// Don't try again.
|
||||
mUri = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override public Matrix getImageMatrix() {
|
||||
if (strict) {
|
||||
throw new UnsupportedOperationException("Not supported");
|
||||
}
|
||||
return super.getImageMatrix();
|
||||
}
|
||||
|
||||
@Override public void setScaleType(ScaleType scaleType) {
|
||||
if (scaleType == ScaleType.CENTER ||
|
||||
scaleType == ScaleType.CENTER_CROP ||
|
||||
scaleType == ScaleType.CENTER_INSIDE) {
|
||||
|
||||
super.setScaleType(scaleType);
|
||||
} else if (strict) {
|
||||
throw new UnsupportedOperationException("Not supported");
|
||||
}
|
||||
}
|
||||
|
||||
@Override public void invalidateDrawable(Drawable dr) {
|
||||
if (strict) {
|
||||
throw new UnsupportedOperationException("Not supported");
|
||||
}
|
||||
super.invalidateDrawable(dr);
|
||||
}
|
||||
|
||||
@Override public int[] onCreateDrawableState(int extraSpace) {
|
||||
if (strict) {
|
||||
throw new UnsupportedOperationException("Not supported");
|
||||
}
|
||||
return super.onCreateDrawableState(extraSpace);
|
||||
}
|
||||
|
||||
@Override public void setAdjustViewBounds(boolean adjustViewBounds) {
|
||||
if (strict) {
|
||||
throw new UnsupportedOperationException("Not supported");
|
||||
}
|
||||
super.setAdjustViewBounds(adjustViewBounds);
|
||||
}
|
||||
|
||||
@Override public void setImageLevel(int level) {
|
||||
if (strict) {
|
||||
throw new UnsupportedOperationException("Not supported");
|
||||
}
|
||||
super.setImageLevel(level);
|
||||
}
|
||||
|
||||
@Override public void setImageMatrix(Matrix matrix) {
|
||||
if (strict) {
|
||||
throw new UnsupportedOperationException("Not supported");
|
||||
}
|
||||
}
|
||||
|
||||
@Override public void setImageState(int[] state, boolean merge) {
|
||||
if (strict) {
|
||||
throw new UnsupportedOperationException("Not supported");
|
||||
}
|
||||
}
|
||||
|
||||
@Override public void setSelected(boolean selected) {
|
||||
if (strict) {
|
||||
throw new UnsupportedOperationException("Not supported");
|
||||
}
|
||||
super.setSelected(selected);
|
||||
}
|
||||
|
||||
@Override public void setOnTouchListener(OnTouchListener l) {
|
||||
this.customOnTouchListener = l;
|
||||
}
|
||||
|
||||
public void setOnReachBoundListener(GestureImageViewTouchListener.OnReachBoundListener onReachBoundListener) {
|
||||
this.onReachBoundListener = onReachBoundListener;
|
||||
}
|
||||
|
||||
public float getCenterX() {
|
||||
return centerX;
|
||||
}
|
||||
|
||||
public float getCenterY() {
|
||||
return centerY;
|
||||
}
|
||||
|
||||
public boolean isLandscape() {
|
||||
return getImageWidth() >= getImageHeight();
|
||||
}
|
||||
|
||||
public boolean isPortrait() {
|
||||
return getImageWidth() <= getImageHeight();
|
||||
}
|
||||
|
||||
public void setStartingScale(float startingScale) {
|
||||
this.startingScale = startingScale;
|
||||
}
|
||||
|
||||
public void setStartingPosition(float x, float y) {
|
||||
this.startX = x;
|
||||
this.startY = y;
|
||||
}
|
||||
|
||||
@Override public void setOnClickListener(OnClickListener l) {
|
||||
this.onClickListener = l;
|
||||
|
||||
if (gestureImageViewTouchListener != null) {
|
||||
gestureImageViewTouchListener.setOnClickListener(l);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the image dimensions are aligned with the orientation of the device.
|
||||
*/
|
||||
public boolean isOrientationAligned() {
|
||||
if (deviceOrientation == Configuration.ORIENTATION_LANDSCAPE) {
|
||||
return isLandscape();
|
||||
} else if (deviceOrientation == Configuration.ORIENTATION_PORTRAIT) {
|
||||
return isPortrait();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public int getDeviceOrientation() {
|
||||
return deviceOrientation;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,30 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2012 Jason Polites
|
||||
*
|
||||
* 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.polites.android;
|
||||
|
||||
/**
|
||||
* @author jasonpolites
|
||||
*
|
||||
*/
|
||||
public interface GestureImageViewListener {
|
||||
|
||||
public void onTouch(float x, float y);
|
||||
|
||||
public void onScale(float scale);
|
||||
|
||||
public void onPosition(float x, float y);
|
||||
|
||||
}
|
||||
|
|
@ -1,549 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2012 Jason Polites
|
||||
*
|
||||
* 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.polites.android;
|
||||
|
||||
import android.content.res.Configuration;
|
||||
import android.graphics.PointF;
|
||||
import android.view.GestureDetector;
|
||||
import android.view.GestureDetector.SimpleOnGestureListener;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
import android.view.View.OnClickListener;
|
||||
import android.view.View.OnTouchListener;
|
||||
|
||||
public class GestureImageViewTouchListener implements OnTouchListener {
|
||||
|
||||
private GestureImageView image;
|
||||
private OnClickListener onClickListener;
|
||||
private OnReachBoundListener onReachBoundListener;
|
||||
private final PointF current = new PointF();
|
||||
private final PointF last = new PointF();
|
||||
private final PointF next = new PointF();
|
||||
private final PointF down = new PointF();
|
||||
private final PointF midpoint = new PointF();
|
||||
|
||||
private final VectorF scaleVector = new VectorF();
|
||||
private final VectorF pinchVector = new VectorF();
|
||||
|
||||
private boolean touched = false;
|
||||
private boolean inZoom = false;
|
||||
|
||||
private float initialDistance;
|
||||
private float lastScale = 1.0f;
|
||||
private float currentScale = 1.0f;
|
||||
|
||||
private float boundaryLeft = 0;
|
||||
private float boundaryTop = 0;
|
||||
private float boundaryRight = 0;
|
||||
private float boundaryBottom = 0;
|
||||
|
||||
private float maxScale = 5.0f;
|
||||
private float minScale = 0.25f;
|
||||
private float fitScaleHorizontal = 1.0f;
|
||||
private float fitScaleVertical = 1.0f;
|
||||
|
||||
private int canvasWidth = 0;
|
||||
private int canvasHeight = 0;
|
||||
|
||||
private float centerX = 0;
|
||||
private float centerY = 0;
|
||||
|
||||
private float startingScale = 0;
|
||||
|
||||
private boolean canDragX = false;
|
||||
private boolean canDragY = false;
|
||||
|
||||
private boolean multiTouch = false;
|
||||
|
||||
private int displayWidth;
|
||||
private int displayHeight;
|
||||
|
||||
private int imageWidth;
|
||||
private int imageHeight;
|
||||
|
||||
private FlingListener flingListener;
|
||||
private FlingAnimation flingAnimation;
|
||||
private ZoomAnimation zoomAnimation;
|
||||
private MoveAnimation moveAnimation;
|
||||
private GestureDetector tapDetector;
|
||||
private GestureDetector flingDetector;
|
||||
private GestureImageViewListener imageListener;
|
||||
|
||||
private int dragSlop = 48;
|
||||
|
||||
public interface OnReachBoundListener {
|
||||
void onReach(View view, int direction);
|
||||
}
|
||||
|
||||
public GestureImageViewTouchListener(final GestureImageView image, int displayWidth, int displayHeight) {
|
||||
super();
|
||||
|
||||
this.image = image;
|
||||
|
||||
this.displayWidth = displayWidth;
|
||||
this.displayHeight = displayHeight;
|
||||
|
||||
this.centerX = (float) displayWidth / 2.0f;
|
||||
this.centerY = (float) displayHeight / 2.0f;
|
||||
|
||||
this.imageWidth = image.getImageWidth();
|
||||
this.imageHeight = image.getImageHeight();
|
||||
|
||||
startingScale = image.getScale();
|
||||
|
||||
currentScale = startingScale;
|
||||
lastScale = startingScale;
|
||||
|
||||
boundaryRight = displayWidth;
|
||||
boundaryBottom = displayHeight;
|
||||
boundaryLeft = 0;
|
||||
boundaryTop = 0;
|
||||
|
||||
next.x = image.getImageX();
|
||||
next.y = image.getImageY();
|
||||
|
||||
flingListener = new FlingListener();
|
||||
flingAnimation = new FlingAnimation();
|
||||
zoomAnimation = new ZoomAnimation();
|
||||
moveAnimation = new MoveAnimation();
|
||||
|
||||
flingAnimation.setListener(new FlingAnimationListener() {
|
||||
@Override public void onMove(float x, float y) {
|
||||
handleDrag(current.x + x, current.y + y);
|
||||
}
|
||||
|
||||
@Override public void onComplete() {
|
||||
}
|
||||
});
|
||||
|
||||
zoomAnimation.setZoom(2.0f);
|
||||
zoomAnimation.setZoomAnimationListener(new ZoomAnimationListener() {
|
||||
@Override public void onZoom(float scale, float x, float y) {
|
||||
if (scale <= maxScale && scale >= minScale) {
|
||||
handleScale(scale, x, y);
|
||||
}
|
||||
}
|
||||
|
||||
@Override public void onComplete() {
|
||||
inZoom = false;
|
||||
handleUp();
|
||||
}
|
||||
});
|
||||
|
||||
moveAnimation.setMoveAnimationListener(new MoveAnimationListener() {
|
||||
|
||||
@Override public void onMove(float x, float y) {
|
||||
image.setPosition(x, y);
|
||||
image.redraw();
|
||||
}
|
||||
});
|
||||
|
||||
tapDetector = new GestureDetector(image.getContext(), new SimpleOnGestureListener() {
|
||||
@Override public boolean onDoubleTap(MotionEvent e) {
|
||||
startZoom(e);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override public boolean onSingleTapConfirmed(MotionEvent e) {
|
||||
if (!inZoom) {
|
||||
if (onClickListener != null) {
|
||||
onClickListener.onClick(image);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
flingDetector = new GestureDetector(image.getContext(), flingListener);
|
||||
imageListener = image.getGestureImageViewListener();
|
||||
|
||||
calculateBoundaries();
|
||||
}
|
||||
|
||||
private void startFling() {
|
||||
flingAnimation.setVelocityX(flingListener.getVelocityX());
|
||||
flingAnimation.setVelocityY(flingListener.getVelocityY());
|
||||
image.animationStart(flingAnimation);
|
||||
}
|
||||
|
||||
private void startZoom(MotionEvent e) {
|
||||
inZoom = true;
|
||||
zoomAnimation.reset();
|
||||
|
||||
float zoomTo;
|
||||
|
||||
if (image.isLandscape()) {
|
||||
if (image.getDeviceOrientation() == Configuration.ORIENTATION_PORTRAIT) {
|
||||
int scaledHeight = image.getScaledHeight();
|
||||
|
||||
if (scaledHeight < canvasHeight) {
|
||||
zoomTo = fitScaleVertical / currentScale;
|
||||
zoomAnimation.setTouchX(e.getX());
|
||||
zoomAnimation.setTouchY(image.getCenterY());
|
||||
} else {
|
||||
zoomTo = fitScaleHorizontal / currentScale;
|
||||
zoomAnimation.setTouchX(image.getCenterX());
|
||||
zoomAnimation.setTouchY(image.getCenterY());
|
||||
}
|
||||
} else {
|
||||
int scaledWidth = image.getScaledWidth();
|
||||
|
||||
if (scaledWidth == canvasWidth) {
|
||||
zoomTo = currentScale * 4.0f;
|
||||
zoomAnimation.setTouchX(e.getX());
|
||||
zoomAnimation.setTouchY(e.getY());
|
||||
} else if (scaledWidth < canvasWidth) {
|
||||
zoomTo = fitScaleHorizontal / currentScale;
|
||||
zoomAnimation.setTouchX(image.getCenterX());
|
||||
zoomAnimation.setTouchY(e.getY());
|
||||
} else {
|
||||
zoomTo = fitScaleHorizontal / currentScale;
|
||||
zoomAnimation.setTouchX(image.getCenterX());
|
||||
zoomAnimation.setTouchY(image.getCenterY());
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (image.getDeviceOrientation() == Configuration.ORIENTATION_PORTRAIT) {
|
||||
|
||||
int scaledHeight = image.getScaledHeight();
|
||||
|
||||
if (scaledHeight == canvasHeight) {
|
||||
zoomTo = currentScale * 4.0f;
|
||||
zoomAnimation.setTouchX(e.getX());
|
||||
zoomAnimation.setTouchY(e.getY());
|
||||
} else if (scaledHeight < canvasHeight) {
|
||||
zoomTo = fitScaleVertical / currentScale;
|
||||
zoomAnimation.setTouchX(e.getX());
|
||||
zoomAnimation.setTouchY(image.getCenterY());
|
||||
} else {
|
||||
zoomTo = fitScaleVertical / currentScale;
|
||||
zoomAnimation.setTouchX(image.getCenterX());
|
||||
zoomAnimation.setTouchY(image.getCenterY());
|
||||
}
|
||||
} else {
|
||||
int scaledWidth = image.getScaledWidth();
|
||||
|
||||
if (scaledWidth < canvasWidth) {
|
||||
zoomTo = fitScaleHorizontal / currentScale;
|
||||
zoomAnimation.setTouchX(image.getCenterX());
|
||||
zoomAnimation.setTouchY(e.getY());
|
||||
} else {
|
||||
zoomTo = fitScaleVertical / currentScale;
|
||||
zoomAnimation.setTouchX(image.getCenterX());
|
||||
zoomAnimation.setTouchY(image.getCenterY());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
zoomAnimation.setZoom(zoomTo);
|
||||
image.animationStart(zoomAnimation);
|
||||
}
|
||||
|
||||
private void stopAnimations() {
|
||||
image.animationStop();
|
||||
}
|
||||
|
||||
@Override public boolean onTouch(View v, MotionEvent event) {
|
||||
|
||||
if (inZoom || inZoom && tapDetector.onTouchEvent(event)) {
|
||||
//if (event.getAction() == MotionEvent.ACTION_DOWN) {
|
||||
// last.x = event.getX();
|
||||
// last.y = event.getY();
|
||||
//} else if (event.getAction() == MotionEvent.ACTION_UP) {
|
||||
// if (event.getX() - last.x > dragSlop) {
|
||||
// callReachBound(Direction.LEFT);
|
||||
// } else if (last.x - event.getX() > dragSlop) {
|
||||
// callReachBound(Direction.RIGHT);
|
||||
// }
|
||||
//}
|
||||
return true;
|
||||
}
|
||||
|
||||
if (event.getPointerCount() == 1 && flingDetector.onTouchEvent(event)) {
|
||||
startFling();
|
||||
}
|
||||
|
||||
if (event.getAction() == MotionEvent.ACTION_UP) {
|
||||
handleUp();
|
||||
} else if (event.getAction() == MotionEvent.ACTION_DOWN) {
|
||||
stopAnimations();
|
||||
down.x = event.getX();
|
||||
down.y = event.getY();
|
||||
last.x = event.getX();
|
||||
last.y = event.getY();
|
||||
|
||||
if (imageListener != null) {
|
||||
imageListener.onTouch(last.x, last.y);
|
||||
}
|
||||
|
||||
touched = true;
|
||||
} else if (event.getAction() == MotionEvent.ACTION_MOVE) {
|
||||
if (event.getPointerCount() > 1) {
|
||||
multiTouch = true;
|
||||
if (initialDistance > 0) {
|
||||
|
||||
pinchVector.set(event);
|
||||
pinchVector.calculateLength();
|
||||
|
||||
float distance = pinchVector.length;
|
||||
|
||||
if (initialDistance != distance) {
|
||||
|
||||
float newScale = (distance / initialDistance) * lastScale;
|
||||
|
||||
if (newScale <= maxScale) {
|
||||
scaleVector.length *= newScale;
|
||||
|
||||
scaleVector.calculateEndPoint();
|
||||
|
||||
scaleVector.length /= newScale;
|
||||
|
||||
float newX = scaleVector.end.x;
|
||||
float newY = scaleVector.end.y;
|
||||
|
||||
handleScale(newScale, newX, newY);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
initialDistance = MathUtils.distance(event);
|
||||
|
||||
MathUtils.midpoint(event, midpoint);
|
||||
|
||||
scaleVector.setStart(midpoint);
|
||||
scaleVector.setEnd(next);
|
||||
|
||||
scaleVector.calculateLength();
|
||||
scaleVector.calculateAngle();
|
||||
|
||||
scaleVector.length /= lastScale;
|
||||
}
|
||||
} else {
|
||||
if (!touched) {
|
||||
touched = true;
|
||||
last.x = event.getX();
|
||||
last.y = event.getY();
|
||||
next.x = image.getImageX();
|
||||
next.y = image.getImageY();
|
||||
} else if (!multiTouch) {
|
||||
if (handleDrag(event.getX(), event.getY())) {
|
||||
image.redraw();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
protected void handleUp() {
|
||||
|
||||
multiTouch = false;
|
||||
|
||||
initialDistance = 0;
|
||||
lastScale = currentScale;
|
||||
|
||||
//TODO can not work when Zoom state
|
||||
if (!canDragX && current.x - down.x > dragSlop) {
|
||||
callReachBound(Direction.LEFT);
|
||||
} else if (!canDragX && down.x - current.x > dragSlop) {
|
||||
callReachBound(Direction.RIGHT);
|
||||
} else if (boundaryTop == 0 && current.x - down.y > dragSlop * 0.7) {
|
||||
callReachBound(Direction.TOP);
|
||||
} else if (boundaryBottom == 0 && down.y - current.x > dragSlop * 0.7) {
|
||||
callReachBound(Direction.BOTTOM);
|
||||
}
|
||||
if (!canDragX) {
|
||||
next.x = centerX;
|
||||
}
|
||||
|
||||
if (!canDragY) {
|
||||
next.y = centerY;
|
||||
}
|
||||
|
||||
boundCoordinates();
|
||||
|
||||
if (!canDragX && !canDragY) {
|
||||
|
||||
if (image.isLandscape()) {
|
||||
currentScale = fitScaleHorizontal;
|
||||
lastScale = fitScaleHorizontal;
|
||||
} else {
|
||||
currentScale = fitScaleVertical;
|
||||
lastScale = fitScaleVertical;
|
||||
}
|
||||
}
|
||||
|
||||
image.setScale(currentScale);
|
||||
image.setPosition(next.x, next.y);
|
||||
|
||||
if (imageListener != null) {
|
||||
imageListener.onScale(currentScale);
|
||||
imageListener.onPosition(next.x, next.y);
|
||||
}
|
||||
|
||||
image.redraw();
|
||||
}
|
||||
|
||||
protected void handleScale(float scale, float x, float y) {
|
||||
|
||||
currentScale = scale;
|
||||
|
||||
if (currentScale > maxScale) {
|
||||
currentScale = maxScale;
|
||||
} else if (currentScale < minScale) {
|
||||
currentScale = minScale;
|
||||
} else {
|
||||
next.x = x;
|
||||
next.y = y;
|
||||
}
|
||||
|
||||
calculateBoundaries();
|
||||
|
||||
image.setScale(currentScale);
|
||||
image.setPosition(next.x, next.y);
|
||||
|
||||
if (imageListener != null) {
|
||||
imageListener.onScale(currentScale);
|
||||
imageListener.onPosition(next.x, next.y);
|
||||
}
|
||||
|
||||
image.redraw();
|
||||
}
|
||||
|
||||
protected boolean handleDrag(float x, float y) {
|
||||
current.x = x;
|
||||
current.y = y;
|
||||
|
||||
float diffX = (current.x - last.x);
|
||||
float diffY = (current.y - last.y);
|
||||
|
||||
if (diffX != 0 || diffY != 0) {
|
||||
|
||||
if (canDragX) next.x += diffX;
|
||||
if (canDragY) next.y += diffY;
|
||||
|
||||
boundCoordinates();
|
||||
|
||||
last.x = current.x;
|
||||
last.y = current.y;
|
||||
|
||||
if (canDragX || canDragY) {
|
||||
image.setPosition(next.x, next.y);
|
||||
|
||||
if (imageListener != null) {
|
||||
imageListener.onPosition(next.x, next.y);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public void reset() {
|
||||
currentScale = startingScale;
|
||||
next.x = centerX;
|
||||
next.y = centerY;
|
||||
calculateBoundaries();
|
||||
image.setScale(currentScale);
|
||||
image.setPosition(next.x, next.y);
|
||||
image.redraw();
|
||||
}
|
||||
|
||||
public float getMaxScale() {
|
||||
return maxScale;
|
||||
}
|
||||
|
||||
public void setMaxScale(float maxScale) {
|
||||
this.maxScale = maxScale;
|
||||
}
|
||||
|
||||
public float getMinScale() {
|
||||
return minScale;
|
||||
}
|
||||
|
||||
public void setMinScale(float minScale) {
|
||||
this.minScale = minScale;
|
||||
}
|
||||
|
||||
public void setOnClickListener(OnClickListener onClickListener) {
|
||||
this.onClickListener = onClickListener;
|
||||
}
|
||||
|
||||
public void setOnReachBoundListener(OnReachBoundListener onReachBoundListener) {
|
||||
this.onReachBoundListener = onReachBoundListener;
|
||||
}
|
||||
|
||||
protected void setCanvasWidth(int canvasWidth) {
|
||||
this.canvasWidth = canvasWidth;
|
||||
}
|
||||
|
||||
protected void setCanvasHeight(int canvasHeight) {
|
||||
this.canvasHeight = canvasHeight;
|
||||
}
|
||||
|
||||
protected void setFitScaleHorizontal(float fitScale) {
|
||||
this.fitScaleHorizontal = fitScale;
|
||||
}
|
||||
|
||||
protected void setFitScaleVertical(float fitScaleVertical) {
|
||||
this.fitScaleVertical = fitScaleVertical;
|
||||
}
|
||||
|
||||
protected void boundCoordinates() {
|
||||
|
||||
if (next.x < boundaryLeft) {
|
||||
next.x = boundaryLeft;
|
||||
} else if (next.x > boundaryRight) {
|
||||
next.x = boundaryRight;
|
||||
}
|
||||
if (next.y < boundaryTop) {
|
||||
next.y = boundaryTop;
|
||||
} else if (next.y > boundaryBottom) {
|
||||
next.y = boundaryBottom;
|
||||
}
|
||||
}
|
||||
|
||||
protected void callReachBound(int direction) {
|
||||
if (onReachBoundListener != null) {
|
||||
onReachBoundListener.onReach(image, direction);
|
||||
}
|
||||
}
|
||||
|
||||
protected void calculateBoundaries() {
|
||||
|
||||
int effectiveWidth = Math.round((float) imageWidth * currentScale);
|
||||
int effectiveHeight = Math.round((float) imageHeight * currentScale);
|
||||
|
||||
canDragX = effectiveWidth > displayWidth;
|
||||
canDragY = effectiveHeight > displayHeight;
|
||||
|
||||
if (canDragX) {
|
||||
float diff = (float) (effectiveWidth - displayWidth) / 2.0f;
|
||||
boundaryLeft = centerX - diff;
|
||||
boundaryRight = centerX + diff;
|
||||
}
|
||||
|
||||
if (canDragY) {
|
||||
float diff = (float) (effectiveHeight - displayHeight) / 2.0f;
|
||||
boundaryTop = centerY - diff;
|
||||
boundaryBottom = centerY + diff;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,73 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2012 Jason Polites
|
||||
*
|
||||
* 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.polites.android;
|
||||
|
||||
import android.graphics.PointF;
|
||||
import android.view.MotionEvent;
|
||||
|
||||
public class MathUtils {
|
||||
|
||||
public static float distance(MotionEvent event) {
|
||||
float x = event.getX(0) - event.getX(1);
|
||||
float y = event.getY(0) - event.getY(1);
|
||||
return (float) Math.sqrt(x * x + y * y);
|
||||
}
|
||||
|
||||
public static float distance(PointF p1, PointF p2) {
|
||||
float x = p1.x - p2.x;
|
||||
float y = p1.y - p2.y;
|
||||
return (float) Math.sqrt(x * x + y * y);
|
||||
}
|
||||
|
||||
public static float distance(float x1, float y1, float x2, float y2) {
|
||||
float x = x1 - x2;
|
||||
float y = y1 - y2;
|
||||
return (float) Math.sqrt(x * x + y * y);
|
||||
}
|
||||
|
||||
public static void midpoint(MotionEvent event, PointF point) {
|
||||
float x1 = event.getX(0);
|
||||
float y1 = event.getY(0);
|
||||
float x2 = event.getX(1);
|
||||
float y2 = event.getY(1);
|
||||
midpoint(x1, y1, x2, y2, point);
|
||||
}
|
||||
|
||||
public static void midpoint(float x1, float y1, float x2, float y2, PointF point) {
|
||||
point.x = (x1 + x2) / 2.0f;
|
||||
point.y = (y1 + y2) / 2.0f;
|
||||
}
|
||||
|
||||
/**
|
||||
* Rotates p1 around p2 by angle degrees.
|
||||
*/
|
||||
public void rotate(PointF p1, PointF p2, float angle) {
|
||||
float px = p1.x;
|
||||
float py = p1.y;
|
||||
float ox = p2.x;
|
||||
float oy = p2.y;
|
||||
p1.x = (float) (Math.cos(angle) * (px - ox) - Math.sin(angle) * (py - oy) + ox);
|
||||
p1.y = (float) (Math.sin(angle) * (px - ox) + Math.cos(angle) * (py - oy) + oy);
|
||||
}
|
||||
|
||||
public static float angle(PointF p1, PointF p2) {
|
||||
return angle(p1.x, p1.y, p2.x, p2.y);
|
||||
}
|
||||
|
||||
public static float angle(float x1, float y1, float x2, float y2) {
|
||||
return (float) Math.atan2(y2 - y1, x2 - x1);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,107 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2012 Jason Polites
|
||||
*
|
||||
* 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.polites.android;
|
||||
|
||||
|
||||
/**
|
||||
* @author Jason Polites
|
||||
*
|
||||
*/
|
||||
public class MoveAnimation implements Animation {
|
||||
|
||||
private boolean firstFrame = true;
|
||||
|
||||
private float startX;
|
||||
private float startY;
|
||||
|
||||
private float targetX;
|
||||
private float targetY;
|
||||
private long animationTimeMS = 100;
|
||||
private long totalTime = 0;
|
||||
|
||||
private MoveAnimationListener moveAnimationListener;
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see com.polites.android.Animation#update(com.polites.android.GestureImageView, long)
|
||||
*/
|
||||
@Override
|
||||
public boolean update(GestureImageView view, long time) {
|
||||
totalTime += time;
|
||||
|
||||
if(firstFrame) {
|
||||
firstFrame = false;
|
||||
startX = view.getImageX();
|
||||
startY = view.getImageY();
|
||||
}
|
||||
|
||||
if(totalTime < animationTimeMS) {
|
||||
|
||||
float ratio = (float) totalTime / animationTimeMS;
|
||||
|
||||
float newX = ((targetX - startX) * ratio) + startX;
|
||||
float newY = ((targetY - startY) * ratio) + startY;
|
||||
|
||||
if(moveAnimationListener != null) {
|
||||
moveAnimationListener.onMove(newX, newY);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
if(moveAnimationListener != null) {
|
||||
moveAnimationListener.onMove(targetX, targetY);
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public void reset() {
|
||||
firstFrame = true;
|
||||
totalTime = 0;
|
||||
}
|
||||
|
||||
|
||||
public float getTargetX() {
|
||||
return targetX;
|
||||
}
|
||||
|
||||
|
||||
public void setTargetX(float targetX) {
|
||||
this.targetX = targetX;
|
||||
}
|
||||
|
||||
|
||||
public float getTargetY() {
|
||||
return targetY;
|
||||
}
|
||||
|
||||
public void setTargetY(float targetY) {
|
||||
this.targetY = targetY;
|
||||
}
|
||||
|
||||
public long getAnimationTimeMS() {
|
||||
return animationTimeMS;
|
||||
}
|
||||
|
||||
public void setAnimationTimeMS(long animationTimeMS) {
|
||||
this.animationTimeMS = animationTimeMS;
|
||||
}
|
||||
|
||||
public void setMoveAnimationListener(MoveAnimationListener moveAnimationListener) {
|
||||
this.moveAnimationListener = moveAnimationListener;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,27 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2012 Jason Polites
|
||||
*
|
||||
* 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.polites.android;
|
||||
|
||||
|
||||
/**
|
||||
* @author Jason Polites
|
||||
*
|
||||
*/
|
||||
public interface MoveAnimationListener {
|
||||
|
||||
public void onMove(float x, float y);
|
||||
|
||||
}
|
||||
|
|
@ -1,62 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2012 Jason Polites
|
||||
*
|
||||
* 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.polites.android;
|
||||
|
||||
import android.graphics.PointF;
|
||||
import android.view.MotionEvent;
|
||||
|
||||
public class VectorF {
|
||||
|
||||
public float angle;
|
||||
public float length;
|
||||
|
||||
public final PointF start = new PointF();
|
||||
public final PointF end = new PointF();
|
||||
|
||||
public void calculateEndPoint() {
|
||||
end.x = (float) (Math.cos(angle) * length + start.x);
|
||||
end.y = (float) (Math.sin(angle) * length + start.y);
|
||||
}
|
||||
|
||||
public void setStart(PointF p) {
|
||||
this.start.x = p.x;
|
||||
this.start.y = p.y;
|
||||
}
|
||||
|
||||
public void setEnd(PointF p) {
|
||||
this.end.x = p.x;
|
||||
this.end.y = p.y;
|
||||
}
|
||||
|
||||
public void set(MotionEvent event) {
|
||||
this.start.x = event.getX(0);
|
||||
this.start.y = event.getY(0);
|
||||
this.end.x = event.getX(1);
|
||||
this.end.y = event.getY(1);
|
||||
}
|
||||
|
||||
public float calculateLength() {
|
||||
length = MathUtils.distance(start, end);
|
||||
return length;
|
||||
}
|
||||
|
||||
public float calculateAngle() {
|
||||
angle = MathUtils.angle(start, end);
|
||||
return angle;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -1,167 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2012 Jason Polites
|
||||
*
|
||||
* 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.polites.android;
|
||||
|
||||
import android.graphics.PointF;
|
||||
|
||||
|
||||
/**
|
||||
* @author Jason Polites
|
||||
*
|
||||
*/
|
||||
public class ZoomAnimation implements Animation {
|
||||
|
||||
private boolean firstFrame = true;
|
||||
|
||||
private float touchX;
|
||||
private float touchY;
|
||||
|
||||
private float zoom;
|
||||
|
||||
private float startX;
|
||||
private float startY;
|
||||
private float startScale;
|
||||
|
||||
private float xDiff;
|
||||
private float yDiff;
|
||||
private float scaleDiff;
|
||||
|
||||
private long animationLengthMS = 200;
|
||||
private long totalTime = 0;
|
||||
|
||||
private ZoomAnimationListener zoomAnimationListener;
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see com.polites.android.Animation#update(com.polites.android.GestureImageView, long)
|
||||
*/
|
||||
@Override
|
||||
public boolean update(GestureImageView view, long time) {
|
||||
if(firstFrame) {
|
||||
firstFrame = false;
|
||||
|
||||
startX = view.getImageX();
|
||||
startY = view.getImageY();
|
||||
startScale = view.getScale();
|
||||
scaleDiff = (zoom * startScale) - startScale;
|
||||
|
||||
if(scaleDiff > 0) {
|
||||
// Calculate destination for midpoint
|
||||
VectorF vector = new VectorF();
|
||||
|
||||
// Set the touch point as start because we want to move the end
|
||||
vector.setStart(new PointF(touchX, touchY));
|
||||
vector.setEnd(new PointF(startX, startY));
|
||||
|
||||
vector.calculateAngle();
|
||||
|
||||
// Get the current length
|
||||
float length = vector.calculateLength();
|
||||
|
||||
// Multiply length by zoom to get the new length
|
||||
vector.length = length*zoom;
|
||||
|
||||
// Now deduce the new endpoint
|
||||
vector.calculateEndPoint();
|
||||
|
||||
xDiff = vector.end.x - startX;
|
||||
yDiff = vector.end.y - startY;
|
||||
}
|
||||
else {
|
||||
// Zoom out to center
|
||||
xDiff = view.getCenterX() - startX;
|
||||
yDiff = view.getCenterY() - startY;
|
||||
}
|
||||
}
|
||||
|
||||
totalTime += time;
|
||||
|
||||
float ratio = (float) totalTime / (float) animationLengthMS;
|
||||
|
||||
if(ratio < 1) {
|
||||
|
||||
if(ratio > 0) {
|
||||
// we still have time left
|
||||
float newScale = (ratio * scaleDiff) + startScale;
|
||||
float newX = (ratio * xDiff) + startX;
|
||||
float newY = (ratio * yDiff) + startY;
|
||||
|
||||
if(zoomAnimationListener != null) {
|
||||
zoomAnimationListener.onZoom(newScale, newX, newY);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
|
||||
float newScale = scaleDiff + startScale;
|
||||
float newX = xDiff + startX;
|
||||
float newY = yDiff + startY;
|
||||
|
||||
if(zoomAnimationListener != null) {
|
||||
zoomAnimationListener.onZoom(newScale, newX, newY);
|
||||
zoomAnimationListener.onComplete();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public void reset() {
|
||||
firstFrame = true;
|
||||
totalTime = 0;
|
||||
}
|
||||
|
||||
public float getZoom() {
|
||||
return zoom;
|
||||
}
|
||||
|
||||
public void setZoom(float zoom) {
|
||||
this.zoom = zoom;
|
||||
}
|
||||
|
||||
public float getTouchX() {
|
||||
return touchX;
|
||||
}
|
||||
|
||||
public void setTouchX(float touchX) {
|
||||
this.touchX = touchX;
|
||||
}
|
||||
|
||||
public float getTouchY() {
|
||||
return touchY;
|
||||
}
|
||||
|
||||
public void setTouchY(float touchY) {
|
||||
this.touchY = touchY;
|
||||
}
|
||||
|
||||
public long getAnimationLengthMS() {
|
||||
return animationLengthMS;
|
||||
}
|
||||
|
||||
public void setAnimationLengthMS(long animationLengthMS) {
|
||||
this.animationLengthMS = animationLengthMS;
|
||||
}
|
||||
|
||||
public ZoomAnimationListener getZoomAnimationListener() {
|
||||
return zoomAnimationListener;
|
||||
}
|
||||
|
||||
public void setZoomAnimationListener(ZoomAnimationListener zoomAnimationListener) {
|
||||
this.zoomAnimationListener = zoomAnimationListener;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,26 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2012 Jason Polites
|
||||
*
|
||||
* 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.polites.android;
|
||||
|
||||
|
||||
/**
|
||||
* @author Jason Polites
|
||||
*
|
||||
*/
|
||||
public interface ZoomAnimationListener {
|
||||
public void onZoom(float scale, float x, float y);
|
||||
public void onComplete();
|
||||
}
|
||||
|
|
@ -1 +0,0 @@
|
|||
/build
|
||||
|
|
@ -1,27 +0,0 @@
|
|||
apply plugin: 'com.android.application'
|
||||
|
||||
android {
|
||||
compileSdkVersion 23
|
||||
buildToolsVersion "23.0.2"
|
||||
|
||||
defaultConfig {
|
||||
applicationId "com.wyx.pdf"
|
||||
minSdkVersion 16
|
||||
targetSdkVersion 23
|
||||
versionCode 1
|
||||
versionName "1.0"
|
||||
}
|
||||
buildTypes {
|
||||
release {
|
||||
minifyEnabled false
|
||||
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compile fileTree(include: ['*.jar'], dir: 'libs')
|
||||
testCompile 'junit:junit:4.12'
|
||||
compile 'com.android.support:appcompat-v7:23.1.1'
|
||||
compile project(':PdfView')
|
||||
}
|
||||
|
|
@ -1,111 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module external.linked.project.id=":pdfviewsample" external.linked.project.path="$MODULE_DIR$" external.root.project.path="$MODULE_DIR$/.." external.system.id="GRADLE" external.system.module.group="Android-Pdf-Viewer-Library" external.system.module.version="unspecified" type="JAVA_MODULE" version="4">
|
||||
<component name="FacetManager">
|
||||
<facet type="android-gradle" name="Android-Gradle">
|
||||
<configuration>
|
||||
<option name="GRADLE_PROJECT_PATH" value=":pdfviewsample" />
|
||||
</configuration>
|
||||
</facet>
|
||||
<facet type="android" name="Android">
|
||||
<configuration>
|
||||
<option name="SELECTED_BUILD_VARIANT" value="debug" />
|
||||
<option name="SELECTED_TEST_ARTIFACT" value="_android_test_" />
|
||||
<option name="ASSEMBLE_TASK_NAME" value="assembleDebug" />
|
||||
<option name="COMPILE_JAVA_TASK_NAME" value="compileDebugSources" />
|
||||
<afterSyncTasks>
|
||||
<task>generateDebugSources</task>
|
||||
</afterSyncTasks>
|
||||
<option name="ALLOW_USER_CONFIGURATION" value="false" />
|
||||
<option name="MANIFEST_FILE_RELATIVE_PATH" value="/src/main/AndroidManifest.xml" />
|
||||
<option name="RES_FOLDER_RELATIVE_PATH" value="/src/main/res" />
|
||||
<option name="RES_FOLDERS_RELATIVE_PATH" value="file://$MODULE_DIR$/src/main/res" />
|
||||
<option name="ASSETS_FOLDER_RELATIVE_PATH" value="/src/main/assets" />
|
||||
</configuration>
|
||||
</facet>
|
||||
</component>
|
||||
<component name="NewModuleRootManager" LANGUAGE_LEVEL="JDK_1_7" inherit-compiler-output="false">
|
||||
<output url="file://$MODULE_DIR$/build/intermediates/classes/debug" />
|
||||
<output-test url="file://$MODULE_DIR$/build/intermediates/classes/test/debug" />
|
||||
<exclude-output />
|
||||
<content url="file://$MODULE_DIR$">
|
||||
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/r/debug" isTestSource="false" generated="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/aidl/debug" isTestSource="false" generated="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/buildConfig/debug" isTestSource="false" generated="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/rs/debug" isTestSource="false" generated="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/build/generated/res/rs/debug" type="java-resource" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/build/generated/res/resValues/debug" type="java-resource" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/r/androidTest/debug" isTestSource="true" generated="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/aidl/androidTest/debug" isTestSource="true" generated="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/buildConfig/androidTest/debug" isTestSource="true" generated="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/rs/androidTest/debug" isTestSource="true" generated="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/build/generated/res/rs/androidTest/debug" type="java-test-resource" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/build/generated/res/resValues/androidTest/debug" type="java-test-resource" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/debug/res" type="java-resource" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/debug/resources" type="java-resource" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/debug/assets" type="java-resource" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/debug/aidl" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/debug/java" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/debug/jni" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/debug/rs" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/testDebug/res" type="java-test-resource" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/testDebug/resources" type="java-test-resource" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/testDebug/assets" type="java-test-resource" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/testDebug/aidl" isTestSource="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/testDebug/java" isTestSource="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/testDebug/jni" isTestSource="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/testDebug/rs" isTestSource="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/main/res" type="java-resource" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/main/resources" type="java-resource" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/main/assets" type="java-resource" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/main/aidl" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/main/java" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/main/jni" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/main/rs" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/res" type="java-test-resource" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/resources" type="java-test-resource" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/assets" type="java-test-resource" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/aidl" isTestSource="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/java" isTestSource="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/jni" isTestSource="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/rs" isTestSource="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/test/res" type="java-test-resource" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/test/resources" type="java-test-resource" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/test/assets" type="java-test-resource" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/test/aidl" isTestSource="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/test/java" isTestSource="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/test/jni" isTestSource="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/test/rs" isTestSource="true" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/assets" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/blame" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/builds" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/bundles" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/classes" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/dependency-cache" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/com.android.support/appcompat-v7/23.1.1/jars" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/com.android.support/support-v4/23.1.1/jars" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/incremental" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/incremental-classes" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/incremental-runtime-classes" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/incremental-verifier" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/instant-run-support" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/jniLibs" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/manifests" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/reload-dex" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/res" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/restart-dex" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/rs" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/symbols" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/transforms" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/outputs" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/tmp" />
|
||||
</content>
|
||||
<orderEntry type="jdk" jdkName="Android API 23 Platform" jdkType="Android SDK" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
<orderEntry type="library" exported="" name="support-v4-23.1.1" level="project" />
|
||||
<orderEntry type="library" exported="" scope="TEST" name="hamcrest-core-1.3" level="project" />
|
||||
<orderEntry type="library" exported="" scope="TEST" name="junit-4.12" level="project" />
|
||||
<orderEntry type="library" exported="" name="support-annotations-23.1.1" level="project" />
|
||||
<orderEntry type="library" exported="" name="appcompat-v7-23.1.1" level="project" />
|
||||
<orderEntry type="module" module-name="PdfView" exported="" />
|
||||
</component>
|
||||
</module>
|
||||
|
|
@ -1,17 +0,0 @@
|
|||
# Add project specific ProGuard rules here.
|
||||
# By default, the flags in this file are appended to flags specified
|
||||
# in /Users/winney/Documents/android-sdk-macosx/tools/proguard/proguard-android.txt
|
||||
# You can edit the include path and order by changing the proguardFiles
|
||||
# directive in build.gradle.
|
||||
#
|
||||
# For more details, see
|
||||
# http://developer.android.com/guide/developing/tools/proguard.html
|
||||
|
||||
# Add any project specific keep options here:
|
||||
|
||||
# If your project uses WebView with JS, uncomment the following
|
||||
# and specify the fully qualified class name to the JavaScript interface
|
||||
# class:
|
||||
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
|
||||
# public *;
|
||||
#}
|
||||
|
|
@ -1,13 +0,0 @@
|
|||
package com.wyx.pdfviewsample;
|
||||
|
||||
import android.app.Application;
|
||||
import android.test.ApplicationTestCase;
|
||||
|
||||
/**
|
||||
* <a href="http://d.android.com/tools/testing/testing_android.html">Testing Fundamentals</a>
|
||||
*/
|
||||
public class ApplicationTest extends ApplicationTestCase<Application> {
|
||||
public ApplicationTest() {
|
||||
super(Application.class);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,23 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="com.wyx.pdfviewsample"
|
||||
>
|
||||
|
||||
<application
|
||||
android:allowBackup="true"
|
||||
android:label="@string/app_name"
|
||||
android:supportsRtl="true"
|
||||
>
|
||||
<activity android:name=".MainActivity">
|
||||
|
||||
</activity>
|
||||
<activity android:name=".Main2Activity">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN"/>
|
||||
<category android:name="android.intent.category.LAUNCHER"/>
|
||||
</intent-filter>
|
||||
|
||||
</activity>
|
||||
</application>
|
||||
|
||||
</manifest>
|
||||
Binary file not shown.
Binary file not shown.
|
|
@ -1,242 +0,0 @@
|
|||
package com.wyx.pdfviewsample;
|
||||
|
||||
import android.os.Environment;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
import android.view.MotionEvent;
|
||||
import java.io.File;
|
||||
import java.io.FileWriter;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* Log record tool
|
||||
*/
|
||||
@SuppressWarnings({ "unused", "ResultOfMethodCallIgnored" }) public class L {
|
||||
|
||||
private static final int LOG_CAT_MAX_LENGTH = 3900;
|
||||
|
||||
private static final String TAG_LINE_BREAK = "****";
|
||||
private static final String EMPTY_LOG = "---";
|
||||
|
||||
private static final String ROOT = Environment.getExternalStorageDirectory().getAbsolutePath();
|
||||
private static final String FILE_NAME = "logger.log";
|
||||
private static final int WRITE_TO_SD_PRIORITY_LEVEL = Log.DEBUG;
|
||||
|
||||
private static String logFile = ROOT + "/" + FILE_NAME;
|
||||
private static boolean write2SdCard = false;
|
||||
private static int write2SdPriorityLevel = WRITE_TO_SD_PRIORITY_LEVEL;
|
||||
|
||||
private static boolean debug = true;
|
||||
|
||||
public static void setDebug(boolean debug) {
|
||||
L.debug = debug;
|
||||
}
|
||||
|
||||
public static void setWrite2SdCard(boolean sdCard) {
|
||||
write2SdCard = sdCard;
|
||||
}
|
||||
|
||||
public static void setWriteToSdPriorityLevel(int level) {
|
||||
write2SdPriorityLevel = level;
|
||||
}
|
||||
|
||||
public static void exception(Throwable e) {
|
||||
if (debug && e != null) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public static void exception(Throwable e, String s) {
|
||||
if (debug && e != null) {
|
||||
e.printStackTrace();
|
||||
e(TAG_LINE_BREAK, s);
|
||||
}
|
||||
}
|
||||
|
||||
public static void w(Object object, Object msg) {
|
||||
if (debug) {
|
||||
print(Log.WARN, object, msg);
|
||||
}
|
||||
}
|
||||
|
||||
public static void w(Object msg) {
|
||||
if (debug) {
|
||||
print(Log.WARN, TAG_LINE_BREAK, msg);
|
||||
}
|
||||
}
|
||||
|
||||
public static void v(Object object, Object msg) {
|
||||
if (debug) {
|
||||
print(Log.VERBOSE, object, msg);
|
||||
}
|
||||
}
|
||||
|
||||
public static void v(Object msg) {
|
||||
if (debug) {
|
||||
print(Log.VERBOSE, TAG_LINE_BREAK, msg);
|
||||
}
|
||||
}
|
||||
|
||||
public static void d(Object object, Object msg) {
|
||||
if (debug) {
|
||||
print(Log.DEBUG, object, msg);
|
||||
}
|
||||
}
|
||||
|
||||
public static void d(Object msg) {
|
||||
if (debug) {
|
||||
print(Log.DEBUG, TAG_LINE_BREAK, msg);
|
||||
}
|
||||
}
|
||||
|
||||
public static void i(Object object, Object msg) {
|
||||
if (debug) {
|
||||
print(Log.INFO, object, msg);
|
||||
}
|
||||
}
|
||||
|
||||
public static void i(Object msg) {
|
||||
if (debug) {
|
||||
print(Log.INFO, TAG_LINE_BREAK, msg);
|
||||
}
|
||||
}
|
||||
|
||||
public static void e(Object object, Object msg) {
|
||||
if (debug) {
|
||||
print(Log.ERROR, object, msg);
|
||||
}
|
||||
}
|
||||
|
||||
public static void e(Object msg) {
|
||||
if (debug) {
|
||||
print(Log.ERROR, TAG_LINE_BREAK, msg);
|
||||
}
|
||||
}
|
||||
|
||||
private static void print(int priority, Object tag, Object msg) {
|
||||
String s = toString(msg);
|
||||
printToLogCat(priority, tag, s);
|
||||
if (write2SdCard) {
|
||||
writeLog(priority, tag, s);
|
||||
}
|
||||
}
|
||||
|
||||
private static void printToLogCat(int priority, Object tag, String s) {
|
||||
if (s.length() > LOG_CAT_MAX_LENGTH) {
|
||||
println(priority, tag, "log length - " + String.valueOf(s.length()));
|
||||
int chunkCount = s.length() / LOG_CAT_MAX_LENGTH; // integer division
|
||||
for (int i = 0; i <= chunkCount; i++) {
|
||||
int max = LOG_CAT_MAX_LENGTH * (i + 1);
|
||||
if (max >= s.length()) {
|
||||
println(priority, "chunk " + i + " of " + chunkCount, s.substring(LOG_CAT_MAX_LENGTH * i, s.length()));
|
||||
} else {
|
||||
println(priority, "chunk " + i + " of " + chunkCount, s.substring(LOG_CAT_MAX_LENGTH * i, max));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
println(priority, tag, s);
|
||||
}
|
||||
}
|
||||
|
||||
public static void resetLogFile() {
|
||||
File file = new File(logFile);
|
||||
file.delete();
|
||||
try {
|
||||
file.createNewFile();
|
||||
} catch (IOException e) {
|
||||
exception(e);
|
||||
}
|
||||
}
|
||||
|
||||
private static void writeLog(int priority, Object tag, String s) {
|
||||
if (TextUtils.isEmpty(s)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (priority < write2SdPriorityLevel) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
File file = new File(logFile);
|
||||
if (!file.exists()) {
|
||||
file.createNewFile();
|
||||
}
|
||||
FileWriter writer = new FileWriter(file, true);
|
||||
writer.flush();
|
||||
writer.close();
|
||||
} catch (IOException e) {
|
||||
exception(e);
|
||||
}
|
||||
}
|
||||
|
||||
private static void println(int priority, Object tag, String s) {
|
||||
Log.println(priority, getTagName(tag), s);
|
||||
}
|
||||
|
||||
private static String getTagName(Object tag) {
|
||||
if (tag instanceof String) {
|
||||
return (String) tag;
|
||||
}
|
||||
|
||||
if (tag instanceof Class<?>) {
|
||||
return ((Class<?>) tag).getSimpleName();
|
||||
} else {
|
||||
return getTagName(tag.getClass());
|
||||
}
|
||||
}
|
||||
|
||||
private static String toString(Object msg) {
|
||||
if (msg == null) {
|
||||
return EMPTY_LOG;
|
||||
}
|
||||
String s = msg.toString();
|
||||
if (s.isEmpty()) {
|
||||
return EMPTY_LOG;
|
||||
} else {
|
||||
return s;
|
||||
}
|
||||
}
|
||||
|
||||
public static void printTouchEvent(MotionEvent ev) {
|
||||
L.e("touch event", actionToString(ev.getAction()));
|
||||
final int pointerCount = ev.getPointerCount();
|
||||
for (int i = 0; i < pointerCount; i++) {
|
||||
L.d("point",
|
||||
"id[" + i + "]=" + ev.getPointerId(i) + ", x[" + i + "]=" + ev.getX(i) + ", y[" + i + "]=" + ev.getY(i));
|
||||
}
|
||||
// L.d("pointer count", pointerCount);
|
||||
}
|
||||
|
||||
public static String actionToString(int action) {
|
||||
switch (action) {
|
||||
case MotionEvent.ACTION_DOWN:
|
||||
return "ACTION_DOWN";
|
||||
case MotionEvent.ACTION_UP:
|
||||
return "ACTION_UP";
|
||||
case MotionEvent.ACTION_CANCEL:
|
||||
return "ACTION_CANCEL";
|
||||
case MotionEvent.ACTION_OUTSIDE:
|
||||
return "ACTION_OUTSIDE";
|
||||
case MotionEvent.ACTION_MOVE:
|
||||
return "ACTION_MOVE";
|
||||
case MotionEvent.ACTION_HOVER_MOVE:
|
||||
return "ACTION_HOVER_MOVE";
|
||||
case MotionEvent.ACTION_SCROLL:
|
||||
return "ACTION_SCROLL";
|
||||
case MotionEvent.ACTION_HOVER_ENTER:
|
||||
return "ACTION_HOVER_ENTER";
|
||||
case MotionEvent.ACTION_HOVER_EXIT:
|
||||
return "ACTION_HOVER_EXIT";
|
||||
}
|
||||
int index = (action & MotionEvent.ACTION_POINTER_INDEX_MASK) >> MotionEvent.ACTION_POINTER_INDEX_SHIFT;
|
||||
switch (action & MotionEvent.ACTION_MASK) {
|
||||
case MotionEvent.ACTION_POINTER_DOWN:
|
||||
return "ACTION_POINTER_DOWN(" + index + ")";
|
||||
case MotionEvent.ACTION_POINTER_UP:
|
||||
return "ACTION_POINTER_UP(" + index + ")";
|
||||
default:
|
||||
return Integer.toString(action);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,41 +0,0 @@
|
|||
package com.wyx.pdfviewsample;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.os.Bundle;
|
||||
import android.view.View;
|
||||
import java.io.IOException;
|
||||
import net.sf.andpdf.pdfviewer.gui.PdfView;
|
||||
import net.sf.andpdf.utils.FileUtils;
|
||||
|
||||
public class Main2Activity extends Activity {
|
||||
|
||||
PdfView pdfView;
|
||||
|
||||
@Override protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.activity_main2);
|
||||
|
||||
pdfView = (PdfView) findViewById(R.id.pdf_view);
|
||||
|
||||
//ViewGroup.LayoutParams params =
|
||||
// new ViewGroup.MarginLayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
|
||||
//GestureImageView view = pdfView.mImageView;
|
||||
//view.setImageResource(R.drawable.back02);
|
||||
//view.setLayoutParams(params);
|
||||
|
||||
//ViewGroup layout = (ViewGroup) findViewById(R.id.layout);
|
||||
|
||||
//layout.addView(view);
|
||||
View view = pdfView.mImageView;
|
||||
}
|
||||
|
||||
@Override protected void onStart() {
|
||||
super.onStart();
|
||||
try {
|
||||
pdfView.parsePDF(FileUtils.fileFromAsset(this, "sample.pdf"), null);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
pdfView.startRenderThread(1, 1.0f);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,58 +0,0 @@
|
|||
package com.wyx.pdfviewsample;
|
||||
|
||||
import java.io.IOException;
|
||||
import net.sf.andpdf.pdfviewer.PdfViewerActivity;
|
||||
import net.sf.andpdf.utils.FileUtils;
|
||||
|
||||
public class MainActivity extends PdfViewerActivity {
|
||||
|
||||
@Override public String getFileName() {
|
||||
try {
|
||||
return FileUtils.fileFromAsset(this, "about.pdf").toString();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override public int getPreviousPageImageResource() {
|
||||
return R.drawable.left_arrow;
|
||||
}
|
||||
|
||||
@Override public int getNextPageImageResource() {
|
||||
return R.drawable.right_arrow;
|
||||
}
|
||||
|
||||
@Override public int getZoomInImageResource() {
|
||||
return R.drawable.zoom_in;
|
||||
}
|
||||
|
||||
@Override public int getZoomOutImageResource() {
|
||||
return R.drawable.zoom_out;
|
||||
}
|
||||
|
||||
@Override public int getPdfPasswordLayoutResource() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override public int getPdfPageNumberResource() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override public int getPdfPasswordEditField() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override public int getPdfPasswordOkButton() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override public int getPdfPasswordExitButton() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override public int getPdfPageNumberEditField() {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1,19 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<RelativeLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:paddingLeft="@dimen/activity_horizontal_margin"
|
||||
android:paddingRight="@dimen/activity_horizontal_margin"
|
||||
android:paddingTop="@dimen/activity_vertical_margin"
|
||||
android:paddingBottom="@dimen/activity_vertical_margin"
|
||||
tools:context="com.wyx.pdfviewsample.MainActivity"
|
||||
>
|
||||
|
||||
<TextView
|
||||
android:text="Hello World!"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
/>
|
||||
</RelativeLayout>
|
||||
|
|
@ -1,18 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:id="@+id/layout"
|
||||
android:orientation="vertical"
|
||||
>
|
||||
|
||||
<net.sf.andpdf.pdfviewer.gui.PdfView
|
||||
android:id="@+id/pdf_view"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_marginTop="20dp"
|
||||
/>
|
||||
|
||||
|
||||
</LinearLayout>
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 3.3 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 2.2 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 4.7 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 7.5 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 10 KiB |
|
|
@ -1,6 +0,0 @@
|
|||
<resources>
|
||||
<!-- Example customization of dimensions originally defined in res/values/dimens.xml
|
||||
(such as screen margins) for screens with more than 820dp of available width. This
|
||||
would include 7" and 10" devices in landscape (~960dp and ~1280dp respectively). -->
|
||||
<dimen name="activity_horizontal_margin">64dp</dimen>
|
||||
</resources>
|
||||
|
|
@ -1,6 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<color name="colorPrimary">#3F51B5</color>
|
||||
<color name="colorPrimaryDark">#303F9F</color>
|
||||
<color name="colorAccent">#FF4081</color>
|
||||
</resources>
|
||||
|
|
@ -1,5 +0,0 @@
|
|||
<resources>
|
||||
<!-- Default screen margins, per the Android Design guidelines. -->
|
||||
<dimen name="activity_horizontal_margin">16dp</dimen>
|
||||
<dimen name="activity_vertical_margin">16dp</dimen>
|
||||
</resources>
|
||||
|
|
@ -1,3 +0,0 @@
|
|||
<resources>
|
||||
<string name="app_name">PdfViewSample</string>
|
||||
</resources>
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
<resources>
|
||||
|
||||
<!-- Base application theme. -->
|
||||
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
|
||||
<!-- Customize your theme here. -->
|
||||
<item name="colorPrimary">@color/colorPrimary</item>
|
||||
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
|
||||
<item name="colorAccent">@color/colorAccent</item>
|
||||
</style>
|
||||
|
||||
</resources>
|
||||
|
|
@ -1,14 +0,0 @@
|
|||
package com.wyx.pdfviewsample;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
/**
|
||||
* To work on unit tests, switch the Test Artifact in the Build Variants view.
|
||||
*/
|
||||
public class ExampleUnitTest {
|
||||
@Test public void addition_isCorrect() throws Exception {
|
||||
assertEquals(4, 2 + 2);
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue