码迷,mamicode.com
首页 > 移动开发 > 详细

android-ImageView的拖动、旋转、缩放、边界回弹、双击缩放、单击销毁及源码下载

时间:2015-08-28 11:08:36      阅读:255      评论:0      收藏:0      [点我收藏+]

标签:imageview   源码   图片缩放回弹拖动   图片双击单击旋转   自定义image   

博客地址:http://blog.csdn.net/u010156024
TouchImageViewActivity 是本人一句一句代码写的,参考了网上大牛的博客。
不过其中的效果是网上没有的,也是本人一直想实现的效果。
* 本实例重写ImageView的触摸事件和手势方法。
* 实现图片的缩放、拖动,双击放大缩小、单击销毁,边界回弹,旋转并实现自动摆正。
* 详细效果请看目录下面的:结果展示动态图.gif
* 其中大部分关键节点都给出了注释,相信大家一看就会很快明白的。
本示例所展示的效果,是网上没有的,请详细查看,并且,本人力求实例简单。
最终的效果目的是模仿QQ聊天记录中图片的展示效果。
如果大家在学习过程中,遇到什么问题,可以到博客下留言或评论,本人都会及时回复的。

先看效果图:
技术分享

技术分享

技术分享

技术分享

整个效果图是我用另一部手机录制的,由于录制比较大,上传不了,然后就截成了GIF文件,大家可以看看效果。

项目代码中有完整的录制视频,大家可以下载下来之后看到。

源码下载

源码下载之后大家如果有什么问题,欢迎留言!本人会尽快回复的。
本篇代码尽量简单,以上效果全在一个类中完成的,整个代码四百多行。代码中,我都尽量多的给出了注释,相信大家一看就懂得。

源码工程中,还有另外一个网上很多项目中采用的自定义ImageView的代码,大家完全可以采用,不过效果没有本人写的代码的效果,并且它的代码有点不易看懂。
废话不多说,本人代码如下:

/**
 * 本实例重写ImageView的触摸事件和手势方法。
 * 实现图片的缩放、拖动,双击放大缩小、单击销毁,边界回弹,旋转并实现自动摆正。
 * 详细效果请看目录下面的:结果展示动态图.gif
 * @author 龙吟在天
 * {@link http://blog.csdn.net/u010156024}
 */
public class TouchImageViewActivity extends Activity {
    /** Called when the activity is first created. */  
    private ImageView touchImageView;
    private float x_down = 0;
    private float y_down = 0;
    private PointF mid = new PointF();
    private float oldDist = 1f;
    private float oldRotation = 0;//第二个手指放下时的两点的旋转角度
    private float rotation = 0;//旋转角度差值
    private float newRotation = 0;
    private float Reset_scale = 1;
    private Matrix matrix = new Matrix();
    private Matrix matrix1 = new Matrix();
    private Matrix savedMatrix = new Matrix();
    private GestureDetector gestureDetector;

    private static final int NONE = 0;
    private static final int DRAG = 1;
    private static final int ZOOM = 2;
    private int mode = NONE;
    private boolean isFangda = false;//双击放大还是缩小
    private int widthScreen;
    private int heightScreen;
    private Bitmap gintama;
    boolean isCheckTopAndBottom,isCheckRightAndLeft;

    @Override  
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        requestWindowFeature(Window.FEATURE_NO_TITLE);
        setContentView(R.layout.show_touchimageview);
        touchImageView = (ImageView) findViewById(R.id.touchimageview);
        gintama = BitmapFactory.decodeResource(getResources(), R.drawable.abc);
        touchImageView.setImageBitmap(gintama);
        /**
         * 使用图片的矩阵类型进行图片的设置,必须设置
         * setScaleType(ScaleType.MATRIX);
         * 网上有说,设置了该类型之后,怎么设置图片在中心位置上?
         * 我的解决方法就是通过代码控制,将图片设置在屏幕中心
         * 具体代码请参看 center(true,true);方法
         */
        touchImageView.setScaleType(ScaleType.MATRIX);
        DisplayMetrics dm = new DisplayMetrics();
        getWindowManager().getDefaultDisplay().getMetrics(dm);
        //获取屏幕的宽和高
        widthScreen = dm.widthPixels;
        heightScreen = dm.heightPixels;
        //初始化图片的矩阵
        matrix.set(touchImageView.getImageMatrix());
        /**
         * 初始化手势
         * 单击  双击 长按
         * 这三个均是手势起作用
         * 如果想要在这三种手势中进行何种操作,
         * 将代码放在对应的方法中即可。
         */
        gestureDetector = new GestureDetector(
                TouchImageViewActivity.this,
                new GestureDetector.SimpleOnGestureListener(){
            @Override
            public boolean onDown(MotionEvent e) {
                return false;
            }
            @Override
            public void onLongPress(MotionEvent e) {
                super.onLongPress(e);
            }
        });
        gestureDetector.setOnDoubleTapListener(new OnDoubleTapListener() {
            @Override
            public boolean onDoubleTapEvent(MotionEvent e) {
                return false;
            }
            /**
             * 双击手势的时候 会触发该方法一次
             * 所以双击手势对应的代码应放在这里
             */
            @Override
            public boolean onDoubleTap(MotionEvent e) {
                mid.x=e.getX();
                mid.y=e.getY();
                matrix1.set(savedMatrix);
                if (isFangda) {
                    matrix1.postScale(0.5f, 0.5f, mid.x, mid.y);//缩小 
                    isFangda = false;
                }else {
                    matrix1.postScale(2f, 2f, mid.x, mid.y);// 放大
                    isFangda = true;
                }
                matrix.set(matrix1);
                center(true, true);
                touchImageView.setImageMatrix(matrix);
                return true;
            }
            /**
             * 单击手势 会触发该方法一次
             * 单击对应的代码应放在这里
             */
            @Override
            public boolean onSingleTapConfirmed(MotionEvent e) {
                //点击图片 销毁activity
                TouchImageViewActivity.this.finish();
                return false;
            }
        });
        /**
         * 初始化 将图片放在屏幕中心位置
         */
        center(true, true);
        /**
         * 图片设置中心之后,重新设置图片的缩放矩阵
         */
        touchImageView.setImageMatrix(matrix);
        /**
         * 设置ImageView的触摸事件
         */
        touchImageView.setOnTouchListener(new OnTouchListener() {
        @SuppressLint("ClickableViewAccessibility")
        @Override
        public boolean onTouch(View v, MotionEvent event) {
            onTouchEvent(event);
            return true;
        }
    });
 }
    public boolean onTouchEvent(MotionEvent event) {
        /**
         * 在这里调用手势的方法
         * 这是手势和触摸事件同时使用的方法
         */
        if (gestureDetector.onTouchEvent(event)) {
            return true;
        }else {
            switch (event.getAction() & MotionEvent.ACTION_MASK) {
            case MotionEvent.ACTION_DOWN:
                mode = DRAG;
                x_down = event.getX();
                y_down = event.getY();
                /**
                 * 单个手指放下,首先保存图片的缩放矩阵到savedMatrix
                 */
                savedMatrix.set(matrix);
                break;
            case MotionEvent.ACTION_POINTER_DOWN:
                mode = ZOOM;
                /**
                 * 第二个手指刚放下时
                 * 计算两个手指间的距离
                 */
                oldDist = spacing(event);
                /**
                 * 第二个手指刚放下时
                 * 计算两个手指见的旋转角度
                 */
                oldRotation = rotation(event);
                savedMatrix.set(matrix);
                /**
                 * 第二个手指刚放下时
                 * 计算两个手指见的中间点坐标,并存在mid中
                 */
                midPoint(mid, event);
                break;
            case MotionEvent.ACTION_MOVE:
                if (mode == ZOOM) {
                    matrix1.set(savedMatrix);
                    /**
                     * 两个手指开始移动
                     * 计算移动后旋转角度
                     */
                    newRotation = rotation(event);
                    /**
                     * 两个角度之差
                     * 即是图片的旋转角度
                     */
                    rotation = newRotation - oldRotation;
                    /**
                     * 计算移动后两点间的中间点
                     */
                    float newDist = spacing(event);
                    /**
                     * 两个中间点的商即时放大倍数
                     */
                    float scale = newDist / oldDist;

                    matrix1.postScale(scale, scale, mid.x, mid.y);// 縮放
                    matrix1.postRotate(rotation, mid.x, mid.y);// 旋轉
                    matrix.set(matrix1);
                    /**
                     * 调用该方法即可重新图片
                     */
                    touchImageView.setImageMatrix(matrix);
                } else if (mode == DRAG) {
                    matrix1.set(savedMatrix);
                    float tx = event.getX() - x_down;
                    float ty = event.getY() - y_down;
                    /**
                     * 单个手指移动后的距离大于20 才算作移动
                     */
                    if (Math.sqrt(tx*tx+ty*ty)>20f) {
                        /**
                         * 设置图片宽高与屏幕宽高的大小的boolean类型的值
                         */
                        isCheckRightAndLeft = isCheckTopAndBottom = true;
                        /**
                         * 得到目前图片的宽高
                         */
                        RectF rectF = getMatrixRectF();
                        /**
                         * 图片宽度小于屏幕大小
                         * 不移动
                         */
                        if (rectF.width()<widthScreen) {
                            tx = 0;
                            isCheckRightAndLeft = false;
                        }
                        /**
                         * 图片高度小于屏幕高度
                         * 不移动
                         */
                        if (rectF.height()<heightScreen) {
                            ty = 0;
                            isCheckTopAndBottom = false;
                        }
                        matrix1.postTranslate(tx,ty);// 平移
                        /**
                         * 如果想在拖动图片的同时检测图片边缘是否
                         * 到达屏幕的边缘,则取消下面的注释
                         */
//                      matrix.set(matrix1);
//                      checkDxDyBounds();
                        matrix.set(matrix1);
                        touchImageView.setImageMatrix(matrix);
                    }
                }
                break;
            case MotionEvent.ACTION_UP:
            case MotionEvent.ACTION_POINTER_UP:
                if (mode == ZOOM) {
                    /**
                     * 双手放开,停止图片的旋转和缩放
                     * Reset_scale还原图片的缩放比例
                     */
                    matrix1.postScale(Reset_scale, Reset_scale, mid.x, mid.y);
                    /**
                     * 双手放开,停止缩放、旋转图片,此时根据已旋转的角度
                     * 计算还原图片的角度,最终的效果是把图片竖直或横平方正。
                     */
                    setRotate();
                    matrix.set(matrix1);
                    /**
                     * 将图片放在屏幕中间位置
                     */
                    center(true, true);
                    touchImageView.setImageMatrix(matrix);
                    matrix1.reset();
                }else if (mode == DRAG) {
                    /**
                     * 单手拖动图片,放开手指,停止拖动
                     * 此时检测图片是否已经偏离屏幕边缘
                     * 如果偏离屏幕边缘,则图片回弹
                     */
                    checkDxDyBounds();
                    matrix.set(matrix1);
                    touchImageView.setImageMatrix(matrix);
                    matrix1.reset();
                }
                mode = NONE;
                break;
            }
            return true;
        }
   }
    /** 
     * 根据当前图片的Matrix获得图片的范围 
     * 这里获取的是当前显示的图片的大小。
     * 图片放大后,获取的就是图片放大后的图片的大小。
     * 图片缩小后,获取的就是图片缩小后的图片的大小。
     * 
     * 这个大小与图片的大小是有区别的。
     * 下面是固定用法,记住即可。
     * @return 
     */  
    private RectF getMatrixRectF()
    {  
        Matrix m = matrix;
        RectF rect = new RectF();
        Drawable d = touchImageView.getDrawable();
        if (null != d)
        {  
            rect.set(0, 0, d.getIntrinsicWidth(), d.getIntrinsicHeight());
        }
        return rect;
    } 
    /**
     * 横向、纵向 图片居中
     */
    protected void center(boolean horizontal, boolean vertical) {
        RectF rect = getMatrixRectF();
        float deltaX = 0, deltaY = 0;
        float height = rect.height();
        float width = rect.width();
        if (vertical) {
            /**
             *  图片小于屏幕大小,则居中显示。
             *  大于屏幕,如果图片上方留空则往上移,
             *  图片下方留空则往下移
             */
            int screenHeight = heightScreen;
            if (height < screenHeight) {
                deltaY = (screenHeight - height) / 2 - rect.top;
            } else if (rect.top > 0) {
                deltaY = -rect.top;
            } else if (rect.bottom < screenHeight) {
                deltaY = touchImageView.getHeight() - rect.bottom;
            }
        }

        if (horizontal) {
            int screenWidth = widthScreen;
            if (width < screenWidth) {
                deltaX = (screenWidth - width) / 2 - rect.left;
            } else if (rect.left > 0) {
                deltaX = -rect.left;
            } else if (rect.right < screenWidth) {
                deltaX = screenWidth - rect.right;
            }
        }
        matrix.postTranslate(deltaX, deltaY);
    }

    // 触碰两点间距离
    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 void midPoint(PointF point, MotionEvent event) {
        float x = event.getX(0) + event.getX(1);
        float y = event.getY(0) + event.getY(1);
        point.set(x/2, y/2);
    }

    // 取旋转角度
    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));
    }
    /**
     * 手指松开,确定旋转的角度
     */
    private void setRotate(){

    }
    /**
     * 检测图片偏离屏幕两边的距离
     * 然后平移,是图片边缘在屏幕边,
     * 使图片周围没有空白
     */
    private void checkDxDyBounds(){
        RectF rectF = getMatrixRectF();
        float dx =0.0f,dy=0.0f;
        /**
         * 如果图片的左侧大于零,说明图片左侧向右
         * 偏离了左侧屏幕,则左移偏离的距离.
         * rectF.left的值,是基于左侧坐标计算的。
         * 图片正常情况下,该值为0.
         * 当图片向右侧拖动以后,该值大于0.
         * 当图片向左侧拖动以后,该值小于0.
         */
        if (rectF.left>0&&isCheckRightAndLeft) {
            dx = -rectF.left;
        }
        /**
         * 如果图片的右侧偏离屏幕的右侧,则
         * 图片右移图片的宽度与图片显示的宽度的差.
         * 
         * rectF.right的值,是基于左侧计算的,图片没有缩放旋转情况下,
         * 该值==touchImageView.getWidth()图片的宽度。
         * 当拖动图片以后,该值变化,等于显示的图片的宽度
         */
        if (rectF.right<touchImageView.getWidth()&&isCheckRightAndLeft) {
            dx=touchImageView.getWidth()-rectF.right;
        }
        /**
         * 当图片顶部大于0,说明图片向下偏离屏幕顶部,
         * 则图片向上回弹偏离的距离。
         * 
         * rectF.top的值基于顶部坐标,
         * 图片正常情况下,该值=0.
         */
        if (rectF.top>0&&isCheckTopAndBottom) {
            dy=-rectF.top;
        }
        /**
         * 当图片底部小于图片高度时,图片偏离屏幕底部
         * 则图片回弹图片的高度与显示的图片的高度之差。
         * 
         * rectF.bottom的值,基于顶部坐标。
         * 图片正常情况下,该值=图片的高度。
         */
        if (rectF.bottom<touchImageView.getHeight()&&isCheckTopAndBottom) {
            dy=touchImageView.getHeight()-rectF.bottom;
        }
    }
}

最后再次给出下载地址:
源码下载
由于是本人花了几天功夫写的,所以代码并没有免费下载,大家见谅!!
大家如果有什么问题,欢迎留言,本人会尽快回复的!^_^【握手】

版权声明:本文为博主原创文章,未经博主允许不得转载。

android-ImageView的拖动、旋转、缩放、边界回弹、双击缩放、单击销毁及源码下载

标签:imageview   源码   图片缩放回弹拖动   图片双击单击旋转   自定义image   

原文地址:http://blog.csdn.net/u010156024/article/details/48047737

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!