文档章节

转载 放大缩小自定义ImageView

徐干稳
 徐干稳
发布于 2016/01/12 14:38
字数 1194
阅读 20
收藏 1
package com.example.tpi;
 
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.PointF;
import android.util.AttributeSet;
import android.util.Log;
import android.view.GestureDetector;
import android.view.GestureDetector.SimpleOnGestureListener;
import android.view.MotionEvent;
import android.view.View;
import android.widget.ImageView;
 
/**
 * @ClassName: MatrixImageView
 * @Description: 带放大、缩小、移动效果的ImageView
 * @author LinJ
 * @date 2015-1-7 上午11:15:07
 * 
 */
public class MatrixImageView extends ImageView {
    private final static String TAG = "MatrixImageView";
    private GestureDetector mGestureDetector;
    /** 模板Matrix,用以初始化 */
    private Matrix mMatrix = new Matrix();
    /** 图片长度 */
    private float mImageWidth;
    /** 图片高度 */
    private float mImageHeight;
 
    public MatrixImageView(Context context, AttributeSet attrs) {
        super(context, attrs);
        MatrixTouchListener mListener = new MatrixTouchListener();
        setOnTouchListener(mListener);
        mGestureDetector = new GestureDetector(getContext(),
                new GestureListener(mListener));
        // 背景设置为balck
        setBackgroundColor(Color.BLACK);
        // 将缩放类型设置为FIT_CENTER,表示把图片按比例扩大/缩小到View的宽度,居中显示
        setScaleType(ScaleType.FIT_CENTER);
    }
 
    @Override
    public void setImageBitmap(Bitmap bm) {
        // TODO Auto-generated method stub
        super.setImageBitmap(bm);
        // 设置完图片后,获取该图片的坐标变换矩阵
        mMatrix.set(getImageMatrix());
        float[] values = new float[9];
        mMatrix.getValues(values);
        // 图片宽度为屏幕宽度除缩放倍数
        mImageWidth = getWidth() / values[Matrix.MSCALE_X];
        mImageHeight = (getHeight() - values[Matrix.MTRANS_Y] * 2)
                / values[Matrix.MSCALE_Y];
    }
 
    public class MatrixTouchListener implements OnTouchListener {
        /** 拖拉照片模式 */
        private static final int MODE_DRAG = 1;
        /** 放大缩小照片模式 */
        private static final int MODE_ZOOM = 2;
        /** 不支持Matrix */
        private static final int MODE_UNABLE = 3;
        /** 最大缩放级别 */
        float mMaxScale = 6;
        /** 双击时的缩放级别 */
        float mDobleClickScale = 2;
        private int mMode = 0;//
        /** 缩放开始时的手指间距 */
        private float mStartDis;
        /** 当前Matrix */
        private Matrix mCurrentMatrix = new Matrix();
 
        /** 用于记录开始时候的坐标位置 */
        private PointF startPoint = new PointF();
 
        @Override
        public boolean onTouch(View v, MotionEvent event) {
            // TODO Auto-generated method stub
            switch (event.getActionMasked()) {
            case MotionEvent.ACTION_DOWN:
                // 设置拖动模式
                mMode = MODE_DRAG;
                //startPoint.set(event.getX(), event.getY());
                isMatrixEnable();
                break;
            case MotionEvent.ACTION_UP:
            case MotionEvent.ACTION_CANCEL:
                reSetMatrix();
                break;
            case MotionEvent.ACTION_MOVE:
                if (mMode == MODE_ZOOM) {
                    setZoomMatrix(event);
                } else if (mMode == MODE_DRAG) {
                    setDragMatrix(event);
                }
                break;
            case MotionEvent.ACTION_POINTER_DOWN:
                if (mMode == MODE_UNABLE)
                    return true;
                mMode = MODE_ZOOM;
                mStartDis = distance(event);
                break;
            default:
                break;
            }
 
            return mGestureDetector.onTouchEvent(event);
        }
 
        public void setDragMatrix(MotionEvent event) {
            if (isZoomChanged()) {
                float dx = event.getX() - startPoint.x; // 得到x轴的移动距离
                float dy = event.getY() - startPoint.y; // 得到x轴的移动距离
                // 避免和双击冲突,大于10f才算是拖动
                if (Math.sqrt(dx * dx + dy * dy) > 10f) {
                    startPoint.set(event.getX(), event.getY());
                    // 在当前基础上移动
                    mCurrentMatrix.set(getImageMatrix());
                    float[] values = new float[9];
                    mCurrentMatrix.getValues(values);
                    dx = checkDxBound(values, dx);
                    dy = checkDyBound(values, dy);
                    mCurrentMatrix.postTranslate(dx, dy);
                    setImageMatrix(mCurrentMatrix);
                }
            }
        }
 
        /**
         * 判断缩放级别是否是改变过
         * 
         * @return true表示非初始值,false表示初始值
         */
        private boolean isZoomChanged() {
            float[] values = new float[9];
            getImageMatrix().getValues(values);
            // 获取当前X轴缩放级别
            float scale = values[Matrix.MSCALE_X];
            // 获取模板的X轴缩放级别,两者做比较
            mMatrix.getValues(values);
            return scale != values[Matrix.MSCALE_X];
        }
 
        /**
         * 和当前矩阵对比,检验dy,使图像移动后不会超出ImageView边界
         * 
         * @param values
         * @param dy
         * @return
         */
        private float checkDyBound(float[] values, float dy) {
            float height = getHeight();
            if (mImageHeight * values[Matrix.MSCALE_Y] < height)
                return 0;
            if (values[Matrix.MTRANS_Y] + dy > 0)
                dy = -values[Matrix.MTRANS_Y];
            else if (values[Matrix.MTRANS_Y] + dy < -(mImageHeight
                    * values[Matrix.MSCALE_Y] - height))
                dy = -(mImageHeight * values[Matrix.MSCALE_Y] - height)
                        - values[Matrix.MTRANS_Y];
            return dy;
        }
 
        /**
         * 和当前矩阵对比,检验dx,使图像移动后不会超出ImageView边界
         * 
         * @param values
         * @param dx
         * @return
         */
        private float checkDxBound(float[] values, float dx) {
            float width = getWidth();
            if (mImageWidth * values[Matrix.MSCALE_X] < width)
                return 0;
            if (values[Matrix.MTRANS_X] + dx > 0)
                dx = -values[Matrix.MTRANS_X];
            else if (values[Matrix.MTRANS_X] + dx < -(mImageWidth
                    * values[Matrix.MSCALE_X] - width))
                dx = -(mImageWidth * values[Matrix.MSCALE_X] - width)
                        - values[Matrix.MTRANS_X];
            return dx;
        }
 
        /**
         * 设置缩放Matrix
         * 
         * @param event
         */
        private void setZoomMatrix(MotionEvent event) {
            // 只有同时触屏两个点的时候才执行
            if (event.getPointerCount() < 2)
                return;
            float endDis = distance(event);// 结束距离
            if (endDis > 10f) { // 两个手指并拢在一起的时候像素大于10
                float scale = endDis / mStartDis;// 得到缩放倍数
                mStartDis = endDis;// 重置距离
                mCurrentMatrix.set(getImageMatrix());// 初始化Matrix
                float[] values = new float[9];
                mCurrentMatrix.getValues(values);
 
                scale = checkMaxScale(scale, values);
                setImageMatrix(mCurrentMatrix);
            }
        }
 
        /**
         * 检验scale,使图像缩放后不会超出最大倍数
         * 
         * @param scale
         * @param values
         * @return
         */
        private float checkMaxScale(float scale, float[] values) {
            if (scale * values[Matrix.MSCALE_X] > mMaxScale)
                scale = mMaxScale / values[Matrix.MSCALE_X];
            mCurrentMatrix.postScale(scale, scale, getWidth() / 2,
                    getHeight() / 2);
            return scale;
        }
 
        /**
         * 重置Matrix
         */
        private void reSetMatrix() {
            if (checkRest()) {
                mCurrentMatrix.set(mMatrix);
                setImageMatrix(mCurrentMatrix);
            }
        }
 
        /**
         * 判断是否需要重置
         * 
         * @return 当前缩放级别小于模板缩放级别时,重置
         */
        private boolean checkRest() {
            // TODO Auto-generated method stub
            float[] values = new float[9];
            getImageMatrix().getValues(values);
            // 获取当前X轴缩放级别
            float scale = values[Matrix.MSCALE_X];
            // 获取模板的X轴缩放级别,两者做比较
            mMatrix.getValues(values);
            return scale < values[Matrix.MSCALE_X];
        }
 
        /**
         * 判断是否支持Matrix
         */
        private void isMatrixEnable() {
            // 当加载出错时,不可缩放
            if (getScaleType() != ScaleType.CENTER) {
                setScaleType(ScaleType.MATRIX);
            } else {
                mMode = MODE_UNABLE;// 设置为不支持手势
            }
        }
 
        /**
         * 计算两个手指间的距离
         * 
         * @param event
         * @return
         */
        private float distance(MotionEvent event) {
            float dx = event.getX(1) - event.getX(0);
            float dy = event.getY(1) - event.getY(0);
            /** 使用勾股定理返回两点之间的距离 */
            return (float) Math.sqrt(dx * dx + dy * dy);
        }
 
        /**
         * 双击时触发
         */
        public void onDoubleClick() {
            float scale = isZoomChanged() ? 1 : mDobleClickScale;
            mCurrentMatrix.set(mMatrix);// 初始化Matrix
            mCurrentMatrix.postScale(scale, scale, getWidth() / 2,
                    getHeight() / 2);
            setImageMatrix(mCurrentMatrix);
        }
    }
 
    private class GestureListener extends SimpleOnGestureListener {
        private final MatrixTouchListener listener;
 
        public GestureListener(MatrixTouchListener listener) {
            this.listener = listener;
        }
 
        @Override
        public boolean onDown(MotionEvent e) {
            // 捕获Down事件
            return true;
        }
 
        @Override
        public boolean onDoubleTap(MotionEvent e) {
            // 触发双击事件
            listener.onDoubleClick();
            return true;
        }
 
        @Override
        public boolean onSingleTapUp(MotionEvent e) {
            // TODO Auto-generated method stub
            return super.onSingleTapUp(e);
        }
 
        @Override
        public void onLongPress(MotionEvent e) {
            // TODO Auto-generated method stub
            super.onLongPress(e);
        }
 
        @Override
        public boolean onScroll(MotionEvent e1, MotionEvent e2,
                float distanceX, float distanceY) {
            return super.onScroll(e1, e2, distanceX, distanceY);
        }
 
        @Override
        public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,
                float velocityY) {
            // TODO Auto-generated method stub
 
            return super.onFling(e1, e2, velocityX, velocityY);
        }
 
        @Override
        public void onShowPress(MotionEvent e) {
            // TODO Auto-generated method stub
            super.onShowPress(e);
        }
 
        @Override
        public boolean onDoubleTapEvent(MotionEvent e) {
            // TODO Auto-generated method stub
            return super.onDoubleTapEvent(e);
        }
 
        @Override
        public boolean onSingleTapConfirmed(MotionEvent e) {
            // TODO Auto-generated method stub
            return super.onSingleTapConfirmed(e);
        }
 
    }
 
}


本文转载自:http://bbs.csdn.net/topics/391079435

徐干稳
粉丝 1
博文 25
码字总数 7783
作品 0
武汉
私信 提问
ImageView的scaleType理解

1.android:scaleType=“center” 保持原图的大小,显示在ImageView的中心。当原图的size大于ImageView的size时,多出来的部分被截掉。 2.android:scaleType=“center_inside” 以原图正常显示...

折痕丶
2018/06/28
0
0
Android之PhtoView设置图片放大缩小后,图片显示在界面上左上角的解决办法

Android之PhtoView设置图片放大缩小后,当调用mAttacher = new PhotoViewAttacher(imageView) 。图片显示在界面上左上角。在网上找了好久也没找到解决办法,看来只能靠自己了。 找到源代码,...

请叫我高级研发工程师
2013/12/16
0
1
图片操作系列 —(1)手势缩放图片功能

概述 项目开发中,大家APP开发一般都会用到上传图片,比如是上传了自己的生活照,然后在某个界面处查看上传的图片,这时候一般在这个查看详情的界面,会有手势放大缩小功能,手势进行旋转功能...

青蛙要fly
2017/11/07
0
0
Android ImageView的scaleType属性与adjustViewBounds属性

ImageView的scaleType的属性有好几种,分别是matrix(默认)、center、centerCrop、centerInside、fitCenter、fitEnd、fitStart、fitXY android:scaleType="center" 保持原图的大小,显示在I......

Erichkko
2015/09/15
2.3K
0
Android开发_拖动效果,旋转效果,两点放大缩小的实现

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/zhangty0223/article/details/9389779 代码主要实现 public boolean onTouch(View v, MotionEvent event) 方法...

张腾元_Ternence
2013/07/20
0
0

没有更多内容

加载失败,请刷新页面

加载更多

Angular 英雄编辑器

应用程序现在有了基本的标题。 接下来你要创建一个新的组件来显示英雄信息并且把这个组件放到应用程序的外壳里去。 创建英雄组件 使用 Angular CLI 创建一个名为 heroes 的新组件。 ng gener...

honeymoose
39分钟前
4
0
Kernel DMA

为什么会有DMA(直接内存访问)?我们知道通常情况下,内存数据跟外设之间的通信是通过cpu来传递的。cpu运行io指令将数据从内存拷贝到外设的io端口,或者从外设的io端口拷贝到内存。由于外设...

yepanl
今天
6
0
hive

一、hive的定义: Hive是一个SQL解析引擎,将SQL语句转译成MR Job,然后再在Hadoop平台上运行,达到快速开发的目的 Hive中的表是纯逻辑表,就只是表的定义,即表的元数据。本质就是Hadoop的目...

霉男纸
今天
3
0
二、Spring Cloud—Eureka(Greenwich.SR1)

注:本系列文章所用工具及版本如下:开发工具(IDEA 2018.3.5),Spring Boot(2.1.3.RELEASE),Spring Cloud(Greenwich.SR1),Maven(3.6.0),JDK(1.8) Eureka: Eureka是Netflix开发...

倪伟伟
昨天
13
0
eclipse常用插件

amaterasUML https://takezoe.github.io/amateras-update-site/ https://github.com/takezoe/amateras-modeler modelGoon https://www.cnblogs.com/aademeng/articles/6890266.html......

大头鬼_yc
昨天
5
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部