基于Android 实现图片平移、缩放、旋转同时进行

前言

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

需求:

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

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

(3)图片在放大缩小的同时都能旋转

Demo实现部分效果截图

Demo主要代码

Java

MainActivity.java
package 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();
    }
  }
  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    initData();
  }
  public void initData() {
    // TODO Auto-generated method stub
    bm = 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);
    }*/
  }
  @Override
  public 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;
  }
  @Override
  protected void onDestroy() {
    // TODO Auto-generated method stub
    super.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;
    @Override
    protected Bitmap doInBackground(File... params) {
      // TODO Auto-generated method stub
      try {
        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 block
        e.printStackTrace();
      }
      return bitmap;
    }
    @Override
    protected void onPostExecute(Bitmap result) {
      // TODO Auto-generated method stub
      EventBus.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.java
package 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
  }
}
(0)

相关推荐

  • Android编程实现图片的浏览、缩放、拖动和自动居中效果

    本文实例讲述了Android编程实现图片的浏览.缩放.拖动和自动居中效果的方法.分享给大家供大家参考,具体如下: Touch.java /** * 图片浏览.缩放.拖动.自动居中 */ public class Touch extends Activity implements OnTouchListener { Matrix matrix = new Matrix(); Matrix savedMatrix = new Matrix(); DisplayMetrics dm; ImageVie

  • Android单点触控实现图片平移、缩放、旋转功能

    相信大家使用多点对图片进行缩放,平移的操作很熟悉了,大部分大图的浏览都具有此功能,有些app还可以对图片进行旋转操作,QQ的大图浏览就可以对图片进行旋转操作,大家都知道对图片进行缩放,平移,旋转等操作可以使用Matrix来实现,Matrix就是一个3X3的矩阵,对图片的处理可分为四个基础变换操作,Translate(平移变换).Rotate(旋转变换).Scale (缩放变换).Skew(错切变换),如果大家对Matrix不太了解的话可以看看这篇文章(点击查看),作者对每一种Matrix的变换写

  • Android 图片缩放与旋转的实现详解

    本文使用Matrix实现Android实现图片缩放与旋转.示例代码如下: 复制代码 代码如下: package com.android.matrix;import android.app.Activity;import android.graphics.Bitmap;import android.graphics.BitmapFactory;import android.graphics.Matrix;import android.graphics.drawable.BitmapDrawable

  • android 图片操作(缩放移动) 实例代码

    view_show.xml 复制代码 代码如下: <?xml version="1.0" encoding="utf-8"?><LinearLayout  xmlns:android="http://schemas.android.com/apk/res/android"  android:orientation="vertical"  android:layout_width="match_par

  • Android实现动态向Gallery中添加图片及倒影与3D效果示例

    本文实例讲述了Android实现动态向Gallery中添加图片及倒影与3D效果的方法.分享给大家供大家参考,具体如下: 在Android中gallery可以提供一个很好的显示图片的方式,实现上面的效果以及动态添加数据库或者网络上下载下来的图片资源.我们首先实现一个自定义的Gallery类. MyGallery.java: package nate.android.Service; import android.content.Context; import android.graphics.Ca

  • Android实现手势滑动多点触摸缩放平移图片效果(二)

    上一篇已经带大家实现了自由的放大缩小图片,简单介绍了下Matrix:具体请参考:Android实现手势滑动多点触摸缩放平移图片效果,本篇继续完善我们的ImageView. 首先加入放大后的移动. 1.自由的进行移动 我们在onTouchEvent里面,加上移动的代码,当然了,必须长或宽大于屏幕才可以移动~~~ @Override public boolean onTouch(View v, MotionEvent event) { mScaleGestureDetector.onTouchEve

  • Android中利用matrix 控制图片的旋转、缩放、移动

    本文主要讲解利用android中Matrix控制图形的旋转缩放移动,具体参见一下代码: 复制代码 代码如下: /**  * 使用矩阵控制图片移动.缩放.旋转  */  public class CommonImgEffectView extends View { private Context context ;      private Bitmap mainBmp , controlBmp ;      private int mainBmpWidth , mainBmpHeight , c

  • Android开发实现图片平移、缩放、倒影及旋转功能的方法

    本文实例讲述了Android开发实现图片平移.缩放.倒影及旋转功能的方法.分享给大家供大家参考,具体如下: 解析: 1)根据原来的图片创建新的图片 Bitmap modBm = Bitmap.createBitmap(bm.getWidth()+20, bm.getHeight()+20, bm.getConfig()); 2)设置到画布 Canvas canvas = new Canvas(modBm); 3)使用矩阵进行平移- Matrix matrix = new Matrix(); ma

  • Android实现手势滑动多点触摸缩放平移图片效果

    现在app中,图片预览功能肯定是少不了的,用户基本已经形成条件反射,看到小图,点击看大图,看到大图两个手指开始进行放大,放大后,开始移动到指定部位. 一.概述 想要做到图片支持多点触控,自由的进行缩放.平移,需要了解几个知识点:Matrix , GestureDetector , ScaleGestureDetector 以及事件分发机制,ps:不会咋办,不会你懂的. 1.Matrix 矩阵,看深入了都是3维矩阵的乘啊什么的,怪麻烦的~~ 其实这么了解下就行了: Matrix 数据结构:3维矩阵

  • Android多点触控实现对图片放大缩小平移,惯性滑动等功能

    文章将在原有基础之上做了一些扩展功能: 1.图片的惯性滑动 2.图片缩放小于正常比例时,松手会自动回弹成正常比例 3.图片缩放大于最大比例时,松手会自动回弹成最大比例 实现图片的缩放,平移,双击缩放等基本功能的代码如下,每一行代码我都做了详细的注释 public class ZoomImageView extends ImageView implements ScaleGestureDetector.OnScaleGestureListener, View.OnTouchListener , V

  • Android实现对图片放大、平移和旋转的功能

    先来看看要实现的效果图 在讲解中,需要大家提前了解一些关于图片绘制的原理的相关知识. 关于实现的流程 1.自定义View 2.获得操作图片的Bitmap 3.复写View的onTouchEvent()方法中的ACTION_DOWN,ACTION_POINTER_DOWN,ACTION_MOVE,ACTION_POINTER_UP以及ACTION_UP事件. 4.定义相应图片变化的Matrix矩阵,通过手势操作的变化来设置相应的Matrix. 5.完成最终的Matrix设置时,通过invalida

随机推荐