android 图片查看器,可通过多点触控实现缩放

先看几张截图:
android <wbr>图片查看器,可通过多点触控实现缩放
          图一:原图
android <wbr>图片查看器,可通过多点触控实现缩放
            图二:两张图片切换的动画
android <wbr>图片查看器,可通过多点触控实现缩放 
            图三:通过手指实现图片放大

布局文件代码:
<?xml version="1.0" encoding="UTF-8"?>
<FrameLayout   xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_height="fill_parent" 
android:layout_width="fill_parent" 
android:orientation="vertical" > 
  <com.lyc.pic.MyGallery android:layout_height="fill_parent" 
  android:layout_width="fill_parent" 
  android:spacing="20px"
  android:id="@+id/mygallery"/> 
</FrameLayout>


两个主要的java类:
Gallery代码
package com.lyc.pic;

import android.content.Context;
import android.graphics.Matrix;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.util.Log;
import android.view.GestureDetector;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.View;
import android.view.GestureDetector.SimpleOnGestureListener;
import android.widget.Gallery;

public class MyGallery extends Gallery {
private GestureDetector gestureScanner; 
private MyImageView imageView;

public MyGallery(Context context) {
super(context);

}

public MyGallery(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}

public MyGallery(Context context, AttributeSet attrs) {
super(context, attrs);

gestureScanner = new GestureDetector(new MySimpleGesture());
this.setOnTouchListener(new OnTouchListener() {

float baseValue;
float originalScale;

//重写onTouch方法实现缩放
@Override
public boolean onTouch(View v, MotionEvent event) {
View view = MyGallery.this.getSelectedView();
if (view instanceof MyImageView) {
imageView = (MyImageView) view;

if (event.getAction() == MotionEvent.ACTION_DOWN) {
baseValue = 0;
originalScale = imageView.getScale();
}
if (event.getAction() == MotionEvent.ACTION_MOVE) {
//处理拖动
if (event.getPointerCount() == 2) {
float x = event.getX(0) - event.getX(1);
float y = event.getY(0) - event.getY(1);
float value = (float) Math.sqrt(x * x + y * y);// 计算两点的距离
// System.out.println("value:" + value);
if (baseValue == 0) {
baseValue = value;
} else {
float scale = value / baseValue;// 当前两点间的距离除以手指落下时两点间的距离就是需要缩放的比例。
// scale the image
imageView.zoomTo(originalScale * scale, x + event.getX(1), y + event.getY(1));

}
}
}
}
return false;
}

});
}
@Override
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
View view = MyGallery.this.getSelectedView();
if (view instanceof MyImageView) {
imageView = (MyImageView) view;

float v[] = new float[9];
Matrix m = imageView.getImageMatrix();
m.getValues(v);
// 图片实时的上下左右坐标
float left, right;
// 图片的实时宽,高
float width, height;
width = imageView.getScale() * imageView.getImageWidth();
height = imageView.getScale() * imageView.getImageHeight();
// 下面逻辑为移动图片和滑动gallery换屏的逻辑。如果没对整个框架了解的非常清晰,勿动以下代码
if ((int) width <= MianActivity.screenWidth && (int) height <= MianActivity.screenHeight)// 如果图片当前大小<屏幕大小,直接处理滑屏事件
{
super.onScroll(e1, e2, distanceX, distanceY);
} else {
left = v[Matrix.MTRANS_X];
right = left + width;
Rect r = new Rect();
imageView.getGlobalVisibleRect(r);

if (distanceX > 0)// 向左滑动
{
if (r.left > 0) {// 判断当前ImageView是否显示完全
super.onScroll(e1, e2, distanceX, distanceY);
} else if (right < MianActivity.screenWidth) {
Log.i("screenWidth", "MianActivity.screenWidth1:" + MianActivity.screenWidth);
super.onScroll(e1, e2, distanceX, distanceY);
} else {
imageView.postTranslate(-distanceX, -distanceY);
}
} else if (distanceX < 0)// 向右滑动
{
if (r.right < MianActivity.screenWidth) {
Log.i("screenWidth", "MianActivity.screenWidth2:" + MianActivity.screenWidth);
super.onScroll(e1, e2, distanceX, distanceY);
} else if (left > 0) {
super.onScroll(e1, e2, distanceX, distanceY);
} else {
imageView.postTranslate(-distanceX, -distanceY);
}
}
// if (distanceX > 0)// 向左滑动
// {
// if (r.left > 0) {// 判断当前ImageView是否显示完全
// super.onScroll(e1, e2, distanceX, distanceY);
// } else if (right <= MianActivity.screenWidth) {
// super.onScroll(e1, e2, distanceX, distanceY);
// } else {
// imageView.postTranslate(-distanceX, -distanceY);
// }
// } else if (distanceX < 0)// 向右滑动
// {
// if (r.right == 0) {
// super.onScroll(e1, e2, distanceX, distanceY);
// } else {
// imageView.postTranslate(-distanceX, -distanceY);
// }
// }
}

} else {
super.onScroll(e1, e2, distanceX, distanceY);
}
return false;
}
@Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
// return false;// 这样会完全除掉fling
int kEvent;
if(isScrollingLeft(e1, e2)){
//Check if scrolling left
kEvent = KeyEvent.KEYCODE_DPAD_LEFT;
} else{
//Otherwise scrolling right
kEvent = KeyEvent.KEYCODE_DPAD_RIGHT;
}
onKeyDown(kEvent, null);
return true;
}
private boolean isScrollingLeft(MotionEvent e1, MotionEvent e2){
return e2.getX() > e1.getX();
}

@Override
public boolean onTouchEvent(MotionEvent event) {
gestureScanner.onTouchEvent(event);
switch (event.getAction()) {
case MotionEvent.ACTION_UP:
// 判断上下边界是否越界
View view = MyGallery.this.getSelectedView();
if (view instanceof MyImageView) {
imageView = (MyImageView) view;
float width = imageView.getScale() * imageView.getImageWidth();
float height = imageView.getScale() * imageView.getImageHeight();
if ((int) width <= MianActivity.screenWidth && (int) height <= MianActivity.screenHeight)// 如果图片当前大小<屏幕大小,判断边界
{
break;
}
float v[] = new float[9];
Matrix m = imageView.getImageMatrix();
m.getValues(v);
float top = v[Matrix.MTRANS_Y];
float bottom = top + height;
if (top > 0) {
imageView.postTranslateDur(-top, 200f);
}
Log.i("lyc", "bottom:" + bottom);
if (bottom < MianActivity.screenHeight) {
imageView.postTranslateDur(MianActivity.screenHeight - bottom, 200f);
}
}
break;
}
return super.onTouchEvent(event);
}

private class MySimpleGesture extends SimpleOnGestureListener {
// 按两下的第二下Touch down时触发
public boolean onDoubleTap(MotionEvent e) {
View view = MyGallery.this.getSelectedView();
if (view instanceof MyImageView) {
imageView = (MyImageView) view;
if (imageView.getScale() > imageView.getScaleRate()) {
imageView.zoomTo(imageView.getScaleRate(), MianActivity.screenWidth / 2, MianActivity.screenHeight / 2, 200f);
// imageView.layoutToCenter();
} else {
imageView.zoomTo(1.0f, MianActivity.screenWidth / 2, MianActivity.screenHeight / 2, 200f);
}
} else {
}
// return super.onDoubleTap(e);
return true;
}
}
}
根据android系统自带的ImageViewTouchBase代码修改的代码:
package com.lyc.pic;

import java.io.InputStream;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.RectF;
import android.os.Handler;
import android.util.AttributeSet;
import android.util.Log;
import android.view.KeyEvent;
import android.widget.ImageView;

public class MyImageView extends ImageView {
@SuppressWarnings("unused")
private static final String TAG = "ImageViewTouchBase";

protected Matrix mBaseMatrix = new Matrix();
protected Matrix mSuppMatrix = new Matrix();
private final Matrix mDisplayMatrix = new Matrix();
private final float[] mMatrixValues = new float[9];

// The current bitmap being displayed.
// protected final RotateBitmap mBitmapDisplayed = new RotateBitmap(null);
protected Bitmap image = null;

int mThisWidth = -1, mThisHeight = -1;
float mMaxZoom = 2.0f;// 最大缩放比例
float mMinZoom ;// 最小缩放比例

private int imageWidth;// 图片的原始宽度
private int imageHeight;// 图片的原始高度

private float scaleRate;// 图片适应屏幕的缩放比例
protected void onDraw(Canvas canvas) {
//正在显示的图片实际宽高
float width = imageWidth*getScale();
float height = imageHeight*getScale();
if (width > MianActivity.screenWidth) {
// 如果图宽大于屏宽,就不用水平居中
center(false, true);
} else {
center(true, true);
}
super.onDraw(canvas);
}


public MyImageView(Context context, int imageWidth, int imageHeight) {
super(context);
this.imageHeight = imageHeight;
this.imageWidth = imageWidth;
init();
}

public MyImageView(Context context, AttributeSet attrs, int imageWidth, int imageHeight) {
super(context, attrs);
this.imageHeight = imageHeight;
this.imageWidth = imageWidth;
init();
}

private void arithScaleRate() {
float scaleWidth = MianActivity.screenWidth / (float) imageWidth;
float scaleHeight = MianActivity.screenHeight / (float) imageHeight;
scaleRate = Math.min(scaleWidth, scaleHeight);
}

public float getScaleRate() {
return scaleRate;
}

public int getImageWidth() {
return imageWidth;
}

public void setImageWidth(int imageWidth) {
this.imageWidth = imageWidth;
}

public int getImageHeight() {
return imageHeight;
}

public void setImageHeight(int imageHeight) {
this.imageHeight = imageHeight;
}

@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK && event.getRepeatCount() == 0) {
event.startTracking();
return true;
}
return super.onKeyDown(keyCode, event);
}

@Override
public boolean onKeyUp(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK && event.isTracking() && !event.isCanceled()) {
if (getScale() > 1.0f) {
// If we're zoomed in, pressing Back jumps out to show the
// entire image, otherwise Back returns the user to the gallery.
zoomTo(1.0f);
return true;
}
}
return super.onKeyUp(keyCode, event);
}

protected Handler mHandler = new Handler();

@Override
public void setImageBitmap(Bitmap bitmap) {
super.setImageBitmap(bitmap);
image = bitmap;
// 计算适应屏幕的比例
arithScaleRate();
//缩放到屏幕大小
zoomTo(scaleRate,MianActivity.screenWidth / 2f, MianActivity.screenHeight / 2f);
//居中
layoutToCenter();
}

protected void center(boolean horizontal, boolean vertical) {
if (image == null) {
return;
}

Matrix m = getImageViewMatrix();

RectF rect = new RectF(0, 0, image.getWidth(), image.getHeight());
m.mapRect(rect);
float height = rect.height();
float width = rect.width();
float deltaX = 0, deltaY = 0;
if (vertical) {
int viewHeight = getHeight();
if (height < viewHeight) {
deltaY = (viewHeight - height) / 2 - rect.top;
} else if (rect.top > 0) {
deltaY = -rect.top;
} else if (rect.bottom < viewHeight) {
deltaY = getHeight() - rect.bottom;
}
}

if (horizontal) {
int viewWidth = getWidth();
if (width < viewWidth) {
deltaX = (viewWidth - width) / 2 - rect.left;
} else if (rect.left > 0) {
deltaX = -rect.left;
} else if (rect.right < viewWidth) {
deltaX = viewWidth - rect.right;
}
}

postTranslate(deltaX, deltaY);
setImageMatrix(getImageViewMatrix());
}

private void init() {
setScaleType(ImageView.ScaleType.MATRIX);
}
public void layoutToCenter()
{
//正在显示的图片实际宽高
float width = imageWidth*getScale();
float height = imageHeight*getScale();
//空白区域宽高
float fill_width = MianActivity.screenWidth - width;
float fill_height = MianActivity.screenHeight - height;
//需要移动的距离
float tran_width = 0f;
float tran_height = 0f;
if(fill_width>0)
tran_width = fill_width/2;
if(fill_height>0)
tran_height = fill_height/2;
postTranslate(tran_width, tran_height);
setImageMatrix(getImageViewMatrix());
}

protected float getValue(Matrix matrix, int whichValue) {
matrix.getValues(mMatrixValues);
mMinZoom =( MianActivity.screenWidth/2f)/imageWidth;
return mMatrixValues[whichValue];
}

// Get the scale factor out of the matrix.
protected float getScale(Matrix matrix) {
return getValue(matrix, Matrix.MSCALE_X);
}

protected float getScale() {
return getScale(mSuppMatrix);
}

// Combine the base matrix and the supp matrix to make the final matrix.
protected Matrix getImageViewMatrix() {
// The final matrix is computed as the concatentation of the base matrix
// and the supplementary matrix.
mDisplayMatrix.set(mBaseMatrix);
mDisplayMatrix.postConcat(mSuppMatrix);
return mDisplayMatrix;
}

static final float SCALE_RATE = 1.25F;

// Sets the maximum zoom, which is a scale relative to the base matrix. It
// is calculated to show the image at 400% zoom regardless of screen or
// image orientation. If in the future we decode the full 3 megapixel image,
// rather than the current 1024x768, this should be changed down to 200%.
protected float maxZoom() {
if (image == null) {
return 1F;
}

float fw = (float) image.getWidth() / (float) mThisWidth;
float fh = (float) image.getHeight() / (float) mThisHeight;
float max = Math.max(fw, fh) * 4;
return max;
}

protected void zoomTo(float scale, float centerX, float centerY) {
if (scale > mMaxZoom) {
scale = mMaxZoom;
} else if (scale < mMinZoom) {
scale = mMinZoom;
}

float oldScale = getScale();
float deltaScale = scale / oldScale;

mSuppMatrix.postScale(deltaScale, deltaScale, centerX, centerY);
setImageMatrix(getImageViewMatrix());
center(true, true);
}

protected void zoomTo(final float scale, final float centerX, final float centerY, final float durationMs) {
final float incrementPerMs = (scale - getScale()) / durationMs;
final float oldScale = getScale();
final long startTime = System.currentTimeMillis();

mHandler.post(new Runnable() {
public void run() {
long now = System.currentTimeMillis();
float currentMs = Math.min(durationMs, now - startTime);
float target = oldScale + (incrementPerMs * currentMs);
zoomTo(target, centerX, centerY);
if (currentMs < durationMs) {
mHandler.post(this);
}
}
});
}

protected void zoomTo(float scale) {
float cx = getWidth() / 2F;
float cy = getHeight() / 2F;

zoomTo(scale, cx, cy);
}

protected void zoomToPoint(float scale, float pointX, float pointY) {
float cx = getWidth() / 2F;
float cy = getHeight() / 2F;

panBy(cx - pointX, cy - pointY);
zoomTo(scale, cx, cy);
}

protected void zoomIn() {
zoomIn(SCALE_RATE);
}

protected void zoomOut() {
zoomOut(SCALE_RATE);
}

protected void zoomIn(float rate) {
if (getScale() >= mMaxZoom) {
return; // Don't let the user zoom into the molecular level.
} else if (getScale() <= mMinZoom) {
return;
}
if (image == null) {
return;
}

float cx = getWidth() / 2F;
float cy = getHeight() / 2F;

mSuppMatrix.postScale(rate, rate, cx, cy);
setImageMatrix(getImageViewMatrix());
}

protected void zoomOut(float rate) {
if (image == null) {
return;
}

float cx = getWidth() / 2F;
float cy = getHeight() / 2F;

// Zoom out to at most 1x.
Matrix tmp = new Matrix(mSuppMatrix);
tmp.postScale(1F / rate, 1F / rate, cx, cy);

if (getScale(tmp) < 1F) {
mSuppMatrix.setScale(1F, 1F, cx, cy);
} else {
mSuppMatrix.postScale(1F / rate, 1F / rate, cx, cy);
}
setImageMatrix(getImageViewMatrix());
center(true, true);
}

public void postTranslate(float dx, float dy) {
mSuppMatrix.postTranslate(dx, dy);
setImageMatrix(getImageViewMatrix());
}
float _dy=0.0f;
protected void postTranslateDur( final float dy, final float durationMs) {
_dy=0.0f;
final float incrementPerMs = dy / durationMs;
final long startTime = System.currentTimeMillis();
mHandler.post(new Runnable() {
public void run() {
long now = System.currentTimeMillis();
float currentMs = Math.min(durationMs, now - startTime);
postTranslate(0, incrementPerMs*currentMs-_dy);
_dy=incrementPerMs*currentMs;

if (currentMs < durationMs) {
mHandler.post(this);
}
}
});
}

protected void panBy(float dx, float dy) {
postTranslate(dx, dy);
setImageMatrix(getImageViewMatrix());
}

}


 

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值