add zoom support

This commit is contained in:
contrudar 2016-10-05 21:04:32 +03:00
parent ee77f0f8fb
commit a8c289a4d9
42 changed files with 40 additions and 2680 deletions

View File

@ -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() {

View File

@ -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 {}

View File

@ -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>

View File

@ -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);
}

View File

@ -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;
}
}

View File

@ -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;
}

View File

@ -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;
}
}

View File

@ -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();
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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);
}

View File

@ -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;
}
}
}

View File

@ -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);
}
}

View File

@ -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;
}
}

View File

@ -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);
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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();
}

View File

@ -1 +0,0 @@
/build

View File

@ -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')
}

View File

@ -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>

View File

@ -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 *;
#}

View File

@ -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);
}
}

View File

@ -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>

View File

@ -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);
}
}
}

View File

@ -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);
}
}

View File

@ -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;
}
}

View File

@ -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>

View File

@ -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

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -1,3 +0,0 @@
<resources>
<string name="app_name">PdfViewSample</string>
</resources>

View File

@ -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>

View File

@ -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);
}
}