Welcome

首页 / 移动开发 / Android / 基于Android 实现图片平移、缩放、旋转同时进行

前言
之前因为项目需求,其中使用到了图片的单击显示取消,图片平移缩放功能,昨天突然想再加上图片的旋转功能,在网上看了很多相关的例子,可是没看到能同时实现我想要的功能的。
需求:

(1)图片平移、缩放、旋转等一系列操作后,图片需要自动居中显示。

(2)图片旋转后选自动水平显示或者垂直显示

(3)图片在放大缩小的同时都能旋转
Demo实现部分效果截图


Demo主要代码

Java

MainActivity.javapackage com.practice.noyet.rotatezoomimageview;import android.app.Activity;import android.graphics.Bitmap;import android.graphics.BitmapFactory;import android.graphics.Matrix;import android.graphics.PointF;import android.graphics.RectF;import android.os.AsyncTask;import android.os.Bundle;import android.util.DisplayMetrics;import android.view.MotionEvent;import android.view.View;import android.widget.ImageView;import com.ypy.eventbus.EventBus;import java.io.File;import java.math.BigDecimal;/*** package: com.practice.noyet.rotatezoomimageview* Created by noyet on 2015/11/11.*/public class MainActivity extends Activity implements View.OnTouchListener {private ImageView mImageView;private PointF point0 = new PointF();private PointF pointM = new PointF();private final int NONE = 0;/** * 平移 */private final int DRAG = 1;/** * 旋转、缩放 */private final int ZOOM = 2;/** * 设定事件模式 */private int mode = NONE;/** * 图片缩放矩阵 */private Matrix matrix = new Matrix();/** * 保存触摸前的图片缩放矩阵 */private Matrix savedMatrix = new Matrix();/** * 保存触点移动过程中的图片缩放矩阵 */private Matrix matrix1 = new Matrix();/** * 屏幕高度 */private int displayHeight;/** * 屏幕宽度 */private int displayWidth;/** * 最小缩放比例 */protected float minScale = 1f;/** * 最大缩放比例 */protected float maxScale = 3f;/** * 当前缩放比例 */protected float currentScale = 1f;/** * 多点触摸2个触摸点间的起始距离 */private float oldDist;/** * 多点触摸时图片的起始角度 */private float oldRotation = 0;/** * 旋转角度 */protected float rotation = 0;/** * 图片初始宽度 */private int imgWidth;/** * 图片初始高度 */private int imgHeight;/** * 设置单点触摸退出图片显示时,单点触摸的灵敏度(可针对不同手机单独设置) */protected final int MOVE_MAX = 2;/** * 单点触摸时手指触发的‘MotionEvent.ACTION_MOVE"次数 */private int fingerNumMove = 0;private Bitmap bm;/** * 保存matrix缩放比例 */private float matrixScale= 1;/*private String imagePath;*//** * 显示被存入缓存中的网络图片 * * @param event 观察者事件 */public void onEventMainThread(CustomEventBus event) {if (event == null) {return;}if (event.type == CustomEventBus.EventType.SHOW_PICTURE) {bm = (Bitmap) event.obj;showImage();}}@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);initData();}public void initData() {// TODO Auto-generated method stubbm = BitmapFactory.decodeResource(getResources(), R.drawable.alipay);DisplayMetrics dm = getResources().getDisplayMetrics();displayWidth = dm.widthPixels;displayHeight = dm.heightPixels;mImageView = (ImageView) findViewById(R.id.image_view);mImageView.setOnTouchListener(this);showImage();//显示网络图片时使用/*File file = MainApplication.getInstance().getImageCache().getDiskCache().get(图片路径);if (!file.exists()) {Toast.makeText(this, "图片路径错误", Toast.LENGTH_SHORT).show();} else {new MyTask().execute(file);}*/}@Overridepublic boolean onTouch(View view, MotionEvent event) {ImageView imageView = (ImageView) view;switch (event.getAction() & MotionEvent.ACTION_MASK) {case MotionEvent.ACTION_DOWN:savedMatrix.set(matrix);point0.set(event.getX(), event.getY());mode = DRAG;System.out.println("MotionEvent--ACTION_DOWN");break;case MotionEvent.ACTION_POINTER_DOWN:oldDist = spacing(event);oldRotation = rotation(event);savedMatrix.set(matrix);setMidPoint(pointM, event);mode = ZOOM;System.out.println("MotionEvent--ACTION_POINTER_DOWN---" + oldRotation);break;case MotionEvent.ACTION_UP:if (mode == DRAG & (fingerNumMove this.finish();}checkView();centerAndRotate();imageView.setImageMatrix(matrix);System.out.println("MotionEvent--ACTION_UP");fingerNumMove = 0;break;case MotionEvent.ACTION_POINTER_UP:mode = NONE;System.out.println("MotionEvent--ACTION_POINTER_UP");break;case MotionEvent.ACTION_MOVE:operateMove(event);imageView.setImageMatrix(matrix1);fingerNumMove++;System.out.println("MotionEvent--ACTION_MOVE");break;}return true;}@Overrideprotected void onDestroy() {// TODO Auto-generated method stubsuper.onDestroy();if (bm != null & !bm.isRecycled()) {bm.recycle(); // 回收图片所占的内存System.gc(); // 提醒系统及时回收}}/** * 显示图片 */private void showImage() {imgWidth = bm.getWidth();imgHeight = bm.getHeight();mImageView.setImageBitmap(bm);matrix.setScale(1, 1);centerAndRotate();mImageView.setImageMatrix(matrix);}/** * 触点移动时的操作 * * @param event 触摸事件 */private void operateMove(MotionEvent event) {matrix1.set(savedMatrix);switch (mode) {case DRAG:matrix1.postTranslate(event.getX() - point0.x, event.getY() - point0.y);break;case ZOOM:rotation = rotation(event) - oldRotation;float newDist = spacing(event);float scale = newDist / oldDist;currentScale = (scale > 3.5f) ? 3.5f : scale;System.out.println("缩放倍数---" + currentScale);System.out.println("旋转角度---" + rotation);/** 縮放 */matrix1.postScale(currentScale, currentScale, pointM.x, pointM.y);/** 旋轉 */matrix1.postRotate(rotation, displayWidth / 2, displayHeight / 2);break;}}/** * 两个触点的距离 * * @param event 触摸事件 * @return float */private float spacing(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);}/** * 获取旋转角度 */private float rotation(MotionEvent event) {double delta_x = (event.getX(0) - event.getX(1));double delta_y = (event.getY(0) - event.getY(1));double radians = Math.atan2(delta_y, delta_x);return (float) Math.toDegrees(radians);}/** * 两个触点的中间坐标 * * @param pointM 中间坐标 * @param event 触摸事件 */private void setMidPoint(PointF pointM, MotionEvent event) {float x = event.getX(0) + event.getY(1);float y = event.getY(0) + event.getY(1);pointM.set(x / 2, y / 2);}/** * 检查约束条件(缩放倍数) */private void checkView() {if (currentScale > 1) {if (currentScale * matrixScale > maxScale) {matrix.postScale(maxScale / matrixScale, maxScale / matrixScale, pointM.x, pointM.y);matrixScale = maxScale;} else {matrix.postScale(currentScale, currentScale, pointM.x, pointM.y);matrixScale *= currentScale;}} else {if (currentScale * matrixScale else {matrix.postScale(currentScale, currentScale, pointM.x, pointM.y);matrixScale *= currentScale;}}}/** * 图片居中显示、判断旋转角度 小于(90 * x + 45)度图片旋转(90 * x)度 大于则旋转(90 * (x+1)) */private void centerAndRotate() {RectF rect = new RectF(0, 0, imgWidth, imgHeight);matrix.mapRect(rect);float width = rect.width();float height = rect.height();float dx = 0;float dy = 0;if (width 2 - width / 2 - rect.left;} else if (rect.left > 0) {dx = -rect.left;} else if (rect.right if (height 2 - height / 2 - rect.top;} else if (rect.top > 0) {dy = -rect.top;} else if (rect.bottom if (rotation != 0) {int rotationNum = (int) (rotation / 90);float rotationAvai = new BigDecimal(rotation % 90).setScale(1, BigDecimal.ROUND_HALF_UP).floatValue();float realRotation = 0;if (rotation > 0) {realRotation = rotationAvai > 45 ? (rotationNum + 1) * 90 : rotationNum * 90;} else if (rotation 0) {realRotation = rotationAvai 45 ? (rotationNum - 1) * 90 : rotationNum * 90;}System.out.println("realRotation: " + realRotation);matrix.postRotate(realRotation, displayWidth / 2, displayHeight / 2);rotation = 0;}}/** * 显示网络图片时使用 */private class MyTask extends AsyncTaskFile, File, Bitmap> {Bitmap bitmap;String path;int scale = 1;long size;@Overrideprotected Bitmap doInBackground(File... params) {// TODO Auto-generated method stubtry {size = params[0].length();path = params[0].getAbsolutePath();BitmapFactory.Options options = new BitmapFactory.Options();options.inJustDecodeBounds = true;BitmapFactory.decodeFile(path, options);scale = calculateInSampleSize(options, displayWidth,displayHeight);options.inJustDecodeBounds = false;options.inSampleSize = scale;bitmap = BitmapFactory.decodeFile(path, options);} catch (Exception e) {// TODO Auto-generated catch blocke.printStackTrace();}return bitmap;}@Overrideprotected void onPostExecute(Bitmap result) {// TODO Auto-generated method stubEventBus.getDefault().post(new CustomEventBus(CustomEventBus.EventType.SHOW_PICTURE, result));}/** * 获取图片缩放比例 * * @param paramOptions Options * @param paramInt1宽 * @param paramInt2高 * @return int */private int calculateInSampleSize(BitmapFactory.Options paramOptions, int paramInt1, int paramInt2) {int i = paramOptions.outHeight;int j = paramOptions.outWidth;int k = 1;if ((i > paramInt2) || (j > paramInt1)) {int m = Math.round(i / paramInt2);int n = Math.round(j / paramInt1);k = m return k;}}}CustomEventBus.javapackage com.practice.noyet.rotatezoomimageview;/*** package: com.practice.noyet.rotatezoomimageview* Created by noyet on 2015/11/11.*/public class CustomEventBus {public EventType type;public Object obj;public CustomEventBus(EventType type, Object obj) {this.type = type;this.obj = obj;}enum EventType {SHOW_PICTURE}}