Android单张图片查看、单指移动、双指缩放、双击最大化或最小化

来源:互联网 发布:linux redis主从配置 编辑:程序博客网 时间:2024/05/18 03:24

Android平台上查看单张图片时,通常情况下需要实现图片查看、单指移动、双指缩放、双击最大化或最小化功能。

目前网络上的实现方式,都没有将此功能封装为类,零落在类和xml文件中,代码难以阅读,功能难以复用。

为此,我专门写了一个类做此功能。此类唯一的缺点是没有实现回弹动画。不说废话了,上代码。

代码如下:

package com.example.test;import android.content.Context;import android.graphics.Bitmap;import android.graphics.Canvas;import android.graphics.Matrix;import android.graphics.PointF;import android.graphics.drawable.BitmapDrawable;import android.util.AttributeSet;import android.util.FloatMath;import android.util.Log;import android.view.MotionEvent;import android.widget.ImageView;public class TouchImageView extends ImageView {private PointF down = new PointF();private PointF mid = new PointF();
private float oldDist = 1f;private Matrix matrix = new Matrix();private Matrix preMatrix = new Matrix();private Matrix savedMatrix = new Matrix();private static final int NONE = 0;private static final int DRAG = 1;private static final int ZOOM = 2;private int mode = NONE;private boolean isBig = false;private int widthScreen;private int heightScreen;private int touchImgWidth;private int touchImgHeight;private float defaultScale;private long lastClickTime = 0;private Bitmap touchImg = null;private static final int DOUBLE_CLICK_TIME_SPACE = 300;private static final int DOUBLE_POINT_DISTANCE = 10;private static float MAX_SCALE = 3.0f;public TouchImageView(Context context) {super(context);}public TouchImageView(Context context, AttributeSet attrs) {super(context, attrs);}public TouchImageView(Context context, AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);}public void initImageView(int screenWidth, int screenHeight) {widthScreen = screenWidth;heightScreen = screenHeight;touchImg = ((BitmapDrawable) getDrawable()).getBitmap();touchImgWidth = touchImg.getWidth();touchImgHeight = touchImg.getHeight();float scaleX = (float) widthScreen / touchImgWidth;float scaleY = (float) heightScreen / touchImgHeight;defaultScale = scaleX < scaleY ? scaleX : scaleY;float subX = (widthScreen - touchImgWidth * defaultScale) / 2;float subY = (heightScreen - touchImgHeight * defaultScale) / 2;setScaleType(ScaleType.MATRIX);preMatrix.reset();preMatrix.postScale(defaultScale, defaultScale);preMatrix.postTranslate(subX, subY);matrix.set(preMatrix);invalidate();}@Overrideprotected void onDraw(Canvas canvas) {if (null != touchImg) {canvas.save();canvas.drawBitmap(touchImg, matrix, null);canvas.restore();}}@Overridepublic boolean onTouchEvent(MotionEvent event) {switch (event.getAction() & MotionEvent.ACTION_MASK) {case MotionEvent.ACTION_DOWN:mode = DRAG;down.x = event.getX();down.y = event.getY();savedMatrix.set(matrix);if (event.getEventTime() - lastClickTime < DOUBLE_CLICK_TIME_SPACE) {changeSize(event.getX(), event.getY());}lastClickTime = event.getEventTime();break;case MotionEvent.ACTION_POINTER_DOWN:oldDist = spacing(event);if (oldDist > DOUBLE_POINT_DISTANCE) {mode = ZOOM;// oldRotation = rotation(event);savedMatrix.set(matrix);midPoint(mid, event);}break;case MotionEvent.ACTION_MOVE:if (mode == ZOOM) {float newDist = spacing(event);float scale = newDist / oldDist;if (scale > 1.01 || scale < 0.99) {preMatrix.set(savedMatrix);preMatrix.postScale(scale, scale, mid.x, mid.y);// 缩放if (canZoom()) {matrix.set(preMatrix);invalidate();}}} else if (mode == DRAG) {if (1.0f < distance(event, down)) {preMatrix.set(savedMatrix);preMatrix.postTranslate(event.getX() - down.x, 0);if (event.getX() > down.x) {if (canDrag(DRAG_RIGHT)) {savedMatrix.set(preMatrix);} else {preMatrix.set(savedMatrix);}} else {if (canDrag(DRAG_LEFT)) {savedMatrix.set(preMatrix);} else {preMatrix.set(savedMatrix);}}preMatrix.postTranslate(0, event.getY() - down.y);if (event.getY() > down.y) {if (canDrag(DRAG_DOWN)) {savedMatrix.set(preMatrix);} else {preMatrix.set(savedMatrix);}} else {if (canDrag(DRAG_TOP)) {savedMatrix.set(preMatrix);} else {preMatrix.set(savedMatrix);}}matrix.set(preMatrix);invalidate();down.x = event.getX();down.y = event.getY();savedMatrix.set(matrix);}}break;case MotionEvent.ACTION_UP:mode = NONE;springback();break;case MotionEvent.ACTION_POINTER_UP:mode = NONE;break;}return true;}private void springback() {preMatrix.set(matrix);float[] x = new float[4];float[] y = new float[4];getFourPoint(x, y);if (x[1] - x[0] > widthScreen) {if (x[0] > 0) {preMatrix.postTranslate(-x[0], 0);matrix.set(preMatrix);invalidate();} else if (x[1] < widthScreen) {preMatrix.postTranslate(widthScreen - x[1], 0);matrix.set(preMatrix);invalidate();}} else if (x[1] - x[0] < widthScreen - 1f) {preMatrix.postTranslate((widthScreen - (x[1] - x[0])) / 2 - x[0], 0);matrix.set(preMatrix);invalidate();}if (y[2] - y[0] > heightScreen) {if (y[0] > 0) {preMatrix.postTranslate(0, -y[0]);matrix.set(preMatrix);invalidate();} else if (y[2] < heightScreen) {preMatrix.postTranslate(0, heightScreen - y[2]);matrix.set(preMatrix);invalidate();}} else if (y[2] - y[0] < heightScreen - 1f) {preMatrix.postTranslate(0, (heightScreen - (y[2] - y[0])) / 2- y[0]);matrix.set(preMatrix);invalidate();}}private void getFourPoint(float[] x, float[] y) {float[] f = new float[9];preMatrix.getValues(f);// 图片4个顶点的坐标x[0] = f[Matrix.MSCALE_X] * 0 + f[Matrix.MSKEW_X] * 0+ f[Matrix.MTRANS_X];y[0] = f[Matrix.MSKEW_Y] * 0 + f[Matrix.MSCALE_Y] * 0+ f[Matrix.MTRANS_Y];x[1] = f[Matrix.MSCALE_X] * touchImg.getWidth() + f[Matrix.MSKEW_X] * 0+ f[Matrix.MTRANS_X];y[1] = f[Matrix.MSKEW_Y] * touchImg.getWidth() + f[Matrix.MSCALE_Y] * 0+ f[Matrix.MTRANS_Y];x[2] = f[Matrix.MSCALE_X] * 0 + f[Matrix.MSKEW_X]* touchImg.getHeight() + f[Matrix.MTRANS_X];y[2] = f[Matrix.MSKEW_Y] * 0 + f[Matrix.MSCALE_Y]* touchImg.getHeight() + f[Matrix.MTRANS_Y];x[3] = f[Matrix.MSCALE_X] * touchImg.getWidth() + f[Matrix.MSKEW_X]* touchImg.getHeight() + f[Matrix.MTRANS_X];y[3] = f[Matrix.MSKEW_Y] * touchImg.getWidth() + f[Matrix.MSCALE_Y]* touchImg.getHeight() + f[Matrix.MTRANS_Y];}private final static int DRAG_LEFT = 0;private final static int DRAG_RIGHT = 1;private final static int DRAG_TOP = 2;private final static int DRAG_DOWN = 3;private boolean canDrag(final int direction) {float[] x = new float[4];float[] y = new float[4];getFourPoint(x, y);// 出界判断if ((x[0] > 0 || x[2] > 0 || x[1] < widthScreen || x[3] < widthScreen)&& (y[0] > 0 || y[1] > 0 || y[2] < heightScreen || y[3] < heightScreen)) {return false;}if (DRAG_LEFT == direction) {// 左移出界判断if (x[1] < widthScreen || x[3] < widthScreen) {return false;}} else if (DRAG_RIGHT == direction) {// 右移出界判断if (x[0] > 0 || x[2] > 0) {return false;}} else if (DRAG_TOP == direction) {// 上移出界判断if (y[2] < heightScreen || y[3] < heightScreen) {return false;}} else if (DRAG_DOWN == direction) {// 下移出界判断if (y[0] > 0 || y[1] > 0) {return false;}} else {return false;}return true;}private boolean canZoom() {float[] x = new float[4];float[] y = new float[4];getFourPoint(x, y);// 图片现宽度double width = Math.sqrt((x[0] - x[1]) * (x[0] - x[1]) + (y[0] - y[1])* (y[0] - y[1]));double height = Math.sqrt((x[0] - x[2]) * (x[0] - x[2]) + (y[0] - y[2])* (y[0] - y[2]));// 缩放比率判断if (width < touchImgWidth * defaultScale - 1|| width > touchImgWidth * MAX_SCALE + 1) {return false;}// 出界判断if (width < widthScreen && height < heightScreen) {return false;}return true;}// 触碰两点间距离private static float spacing(MotionEvent event) {float x = event.getX(0) - event.getX(1);if (x < 0) {x = -x;}float y = event.getY(0) - event.getY(1);if (y < 0) {y = -y;}return FloatMath.sqrt(x * x + y * y);}// 取手势中心点private static void midPoint(PointF point, MotionEvent event) {float x = event.getX(0) + event.getX(1);float y = event.getY(0) + event.getY(1);point.set(x / 2, y / 2);}// 取两点之间的距离private static float distance(MotionEvent point2, PointF point1) {float x = point1.x - point2.getX();if (x < 0) {x = -x;}float y = point1.y - point2.getY();if (y < 0) {y = -y;}return FloatMath.sqrt(x * x + y * y);}private void changeSize(float x, float y) {if (isBig) {float subX = (widthScreen - touchImgWidth * defaultScale) / 2;float subY = (heightScreen - touchImgHeight * defaultScale) / 2;preMatrix.reset();preMatrix.postScale(defaultScale, defaultScale);preMatrix.postTranslate(subX, subY);matrix.set(preMatrix);invalidate();isBig = false;} else {float transX = (widthScreen - touchImgWidth * MAX_SCALE) / 2;float transY = (heightScreen - touchImgHeight * MAX_SCALE) / 2;preMatrix.reset();preMatrix.postScale(MAX_SCALE, MAX_SCALE);preMatrix.postTranslate(transX, transY);matrix.set(preMatrix);invalidate();isBig = true;}}}



测试代码如下:


activity_main.xml文件:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"    xmlns:tools="http://schemas.android.com/tools"    android:id="@+id/layout_id"    android:layout_width="match_parent"    android:layout_height="match_parent"    tools:context=".MainActivity" >    <com.example.test.TouchImageView        android:id="@+id/img_id"        android:layout_width="400dip"        android:layout_height="800dip"        android:src="@drawable/banner"        android:scaleType="fitCenter" /></LinearLayout>


MainActivity.java文件:

package com.example.test;import android.app.Activity;import android.os.Bundle;import android.util.DisplayMetrics;import android.view.Menu;import android.view.ViewTreeObserver.OnGlobalLayoutListener;import android.widget.LinearLayout;public class MainActivity extends Activity {private TouchImageView imgView;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);DisplayMetrics dm = new DisplayMetrics();getWindowManager().getDefaultDisplay().getMetrics(dm);TouchImageView imgView = (TouchImageView) findViewById(R.id.img_id);imgView.initImageView(dm.widthPixels, dm.heightPixels - 80);}@Overridepublic boolean onCreateOptionsMenu(Menu menu) {// Inflate the menu; this adds items to the action bar if it is present.getMenuInflater().inflate(R.menu.main, menu);return true;}}


3 0
原创粉丝点击