Android中實現圖片平移、縮放、旋轉同步進行

jopen 10年前發布 | 21K 次閱讀 Android Android開發 移動開發

轉載請注明轉自:noyet12的博客
博客原址:http://blog.csdn.net/u012975705/article/details/49797911
源碼下載地址:
(github)https://github.com/noyo/RotateZoomImageView
(csdn)http://download.csdn.net/detail/u012975705/9263323
EventBus2.4.jar下載

前言

之前因為項目需求,其中使用到了圖片的單擊顯示取消,圖片平移縮放功能,昨天突然想再加上圖片的旋轉功能,在網上看了很多相關的例子,可是沒看到能同時實現我想要的功能的。
需求:
(1)圖片平移、縮放、旋轉等一系列操作后,圖片需要自動居中顯示。
(2)圖片旋轉后選自動水平顯示或者垂直顯示
(3)圖片在放大縮小的同時都能旋轉

Demo實現部分效果截圖

這里寫圖片描述

Demo主要代碼

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 <= MOVE_MAX)) {
               MainActivity.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 < minScale) {
           matrix.postScale(minScale / matrixScale, minScale / matrixScale, pointM.x, pointM.y);
           matrixScale = minScale;
       } 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 < displayWidth) {

       dx = displayWidth / 2 - width / 2 - rect.left;
      

      } else if (rect.left > 0) {

       dx = -rect.left;
      

      } else if (rect.right < displayWidth) {

       dx = displayWidth - rect.right;
      

      }

      if (height < displayHeight) {

       dy = displayHeight / 2 - height / 2 - rect.top;
      

      } else if (rect.top > 0) {

       dy = -rect.top;
      

      } else if (rect.bottom < displayHeight) {

       dy = displayHeight - rect.bottom;
      

      }

      matrix.postTranslate(dx, dy);

      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 AsyncTask<File, 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 < n ? n : m;
        
        } return k; } } }</pre>
        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
    

    } }</pre>

 本文由用戶 jopen 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!