Android中对图片的操作,移动、缩放,边界限制

一、实现效果

对图片的操作,移动、缩放,边界限制

二、实现方法

监听用户手势,提取用户操作
(1)移动: 分别计算X,Y轴的结束与初始之间移动偏移的量
(2)缩放:(结束两指间距离×伸缩比例)/ 初始两指间距离,scaleX,scaleY放大多少倍
(3)涂鸦:重写onDraw()方法,画布(canvas)结合画笔(Paint)构造Path实现,监听手势起始点坐标与结束坐标,使用path类的quadTo()方法绘制曲线
(4)保存:保存图片Insert到MediaStore.Images.Media下面,广播通知系统相册图库刷新数据

三、移动缩放,边界限制

Android中对图片的操作,移动、缩放,边界限制_第1张图片
注意:仅展示核心代码,请重点关注手势监听部分

通过 Matrix 矩阵 方式操作图片

import android.graphics.Matrix;
import android.graphics.PointF;
import android.util.Log;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.widget.ImageView;
import android.widget.RelativeLayout;
import com.nostra13.universalimageloader.core.ImageLoader;

import org.droidparts.annotation.inject.InjectView;
    private static final String TAG = "mylog_showPic";
    @InjectView(id = R.id.iv_pic,click = true)
    ImageView ivPic;

    private static final int NONE = 0;
    private static final int DRAG = 1; //一个手指
    private static final int MOVE = 3; //移动
    private static final int ZOOM = 2; //两个手指
    private int mode = NONE;

    private Matrix matrix = new Matrix();  //移动的矩阵
    private Matrix saveMatrix = new Matrix();
    private PointF startPoint = new PointF(); //第一个按下手指的点
    private PointF midPoint = new PointF();  // 两个按下手指触摸点的中点
    private float distance = 1f; //两个手指触摸点之间的距离

ImageView图片控件上的手势监听

        ivPic.setOnLongClickListener(new View.OnLongClickListener() {
            @Override
            public boolean onLongClick(View view) {
                return true;
            }
        });
        ivPic.setOnTouchListener((view, motionEvent) -> {
            ImageView imageView = (ImageView) view;
            imageView.setScaleType(ImageView.ScaleType.MATRIX);  //注意:操作之前需设置ScaleType为matrix
//            final int x = (int) motionEvent.getRawX();  //触摸点到屏幕左边的距离
//            final int y = (int) motionEvent.getRawY();  //触摸点到屏幕上边的距离
//            Log.i(TAG,"触摸点离屏幕左边的距离:"+ x +"屏幕上方的距离:"+ y);
            switch (motionEvent.getAction() & MotionEvent.ACTION_MASK){
                case MotionEvent.ACTION_DOWN:
                    Log.i(TAG,"单点按下");
                    //单点按下
                    mode = DRAG;
                    //设置要操作的矩阵为该图片的图片矩阵
                    matrix.set(imageView.getImageMatrix());
                    saveMatrix.set(matrix);
                    startPoint.set(motionEvent.getX(),motionEvent.getY());
                    break;
                case MotionEvent.ACTION_POINTER_DOWN:
                    //多点按下
                    Log.i(TAG,"多点按下");
                    //计算两指间距离
                    distance = distance(motionEvent);
                    if (distance > 10f){
                        saveMatrix.set(matrix);
                        //计算两指间中点的坐标
                        midPoint = midPoint(motionEvent);
                        mode = ZOOM;
                    }
                    break;
                case MotionEvent.ACTION_MOVE:
                    //手指滑动
                    if (mode == DRAG  || mode == MOVE){
                        Log.i(TAG,"移动");
                        mode = MOVE;
                        //获取当前图片矩阵
                        matrix.set(saveMatrix);
                        //分别在x、y轴上将图片矩阵移动相应的距离
                        matrix.postTranslate(motionEvent.getX() - startPoint.x,motionEvent.getY() - startPoint.y);
                        //仅设置左右移动
                        //matrix.postTranslate(motionEvent.getX() - startPoint.x,0);
                    }else if(mode == ZOOM){
                        Log.i(TAG,"缩放");
                        float newDistance = distance(motionEvent);
                        if (newDistance > 10f){
                            //获取当前图片矩阵
                            matrix.set(saveMatrix);
                            //放大或缩小的倍数(缩放后手指间的距离/缩放前手指间的距离)
                            float scale = newDistance/distance;
                            //以两指中点为中心将当前图片矩阵放大或缩小scale倍
                            matrix.postScale(scale,scale,midPoint.x,midPoint.y);
                        }
                    }
                    break;
                case MotionEvent.ACTION_UP:
                	if (mode == DRAG){
                        //是单点按下抬起时候,关闭图片
                        dismiss();
                    }else if (mode == MOVE){
                        //解决鸿蒙系统手机点击图片不能关闭的问题
                        if (isHarmonyOs() || matrix == saveMatrix){
                            //是鸿蒙系统且矩阵未变化
                            dismiss();
                        }
                    }
                    mode = NONE;
                    break;
                case MotionEvent.ACTION_POINTER_UP:
                    //手指抬起
                    mode = NONE;
                    break;
                default:
                    break;
            }
            if (mode == ZOOM){
                float[] values = new float[9];
                matrix.getValues(values);
                float x = ivPic.getDrawable().getBounds().width() * values[0];
                float y = ivPic.getDrawable().getBounds().height() * values[0];
                Log.i(TAG,"当前图片矩阵大小:"+x+"____"+y);
                if (x < 400){
                    Log.i(TAG,"不能缩小了");
                    imageView.setImageMatrix(saveMatrix);
                }else{
                    //将操作后的图片矩阵赋值给imageView
                    imageView.setImageMatrix(matrix);
                }
            }
            else if (mode == DRAG || mode == MOVE){
                float[] values = new float[9];
                matrix.getValues(values);
                float parentWidth = context.getResources().getDisplayMetrics().widthPixels;
                float x = ivPic.getDrawable().getBounds().width() * values[0];
                Log.i(TAG,"当前图片左边位置:"+values[Matrix.MTRANS_X]+"___图片宽度"+x);
                if (values[Matrix.MTRANS_X]< parentWidth && values[Matrix.MTRANS_X] > x*(-1)){
                    //将操作后的图片矩阵赋值给imageView
                    imageView.setImageMatrix(matrix);
                }else{
                	Log.i(TAG,"不能移动了");
                    imageView.setImageMatrix(saveMatrix);
                }
            }
            return true;
        });

判断是否是鸿蒙系统的手机

 /**
     * 是否是鸿蒙系统
     * @return
     */
    public static boolean isHarmonyOs() {
        try {
            Class buildExClass = Class.forName("com.huawei.system.BuildEx");
            Object osBrand = buildExClass.getMethod("getOsBrand").invoke(buildExClass);
            return "Harmony".equalsIgnoreCase(osBrand.toString());
        } catch (Throwable x) {
            return false;
        }
    }

计算两指间距离

    private float distance(MotionEvent motionEvent){
        float dx = motionEvent.getX(0) - motionEvent.getX(1);
        float dy = motionEvent.getY(0) - motionEvent.getY(1);
        return (float) Math.sqrt(dx * dx + dy * dy);
    }

计算两指间中点的坐标

    private PointF midPoint(MotionEvent motionEvent){
        float midx = (motionEvent.getX(0) + motionEvent.getX(1)) / 2;
        float midy = (motionEvent.getY(0) + motionEvent.getY(1)) / 2;
        return new PointF(midx,midy);
    }

控件布局,注意根据情况设置scaleType

   

    


打开图片的方法,可自定义
注意:再次打开照片时,可重新设置ScaleType恢复原始图片大小,不然就会显示上一次图片关闭前缩放操作的图片

public void showAtLocation(View parent, String path) {
        //恢复到原始图片显示大小和位置
        ivPic.setScaleType(ImageView.ScaleType.FIT_CENTER);
        if (TextUtil.isEmpty(path)) {
            return;
        }
        if (!PublicUtils.isImage(path)) {
            return;
        }
        if (path.startsWith("http://")) {
            ImageLoader.getInstance().displayImage(path, ivPic, ImageLoaderUtil.getInstence().getRectOptions());
        } else {
            ImageLoader.getInstance().displayImage("file://" + path, ivPic, ImageLoaderUtil.getInstence().getRectOptions());
        }
        super.showAtLocation(parent, Gravity.CENTER, 0, 0);

    }

四、涂鸦,保存到本地

涂鸦和保存到本地的功能,可以参考我自己使用kotlin语言写的小demo
简易相册demo
本项目实现一个简易的相册功能,一共三个页面,第一个,拍照页,显示在左下角,第二个,图片展示页,图片显示3列,以文件修改时间降序,竖直排列,可上下滑动;第三个,当前选择图片的操作页,可移动,缩放,涂鸦,保存。

五、完成,Nice!

你可能感兴趣的:(Android,安卓控件,android,手势监听,安卓控件)