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;
        }
    }
}
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
    }
}
  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 6
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值