分享

实现Android图片预览的拖拽缩放

 JS资料库 2014-10-20

大多android应用都会有“查看原图”的功能,因原图通常都大于手机屏幕,所以就需要有拖拽,缩放的操作来满足原图的预览。大图预览的一个原则就是:尽量在手机屏幕上居中呈现完整的原图。

由于原图大小和手机屏幕的大小不一,在初始化的时候会出现下面几种处理方式(绿色为手机屏幕,红色为图片)。

1.图片高小于屏幕,宽大于屏幕

 

2.图片高大于屏幕,宽小于屏幕

 

3.图片高和宽都小于屏幕

 

4.图片高和宽都大于屏幕(又分两种情况)

 

 

图片的高和宽的缩放都是同比例的,而且所有缩放后的图片都是居中显示的。对图片进行缩放,拖拽时还有校验操作,比如下面的情况:

 

如果图片和屏幕边框之间有空白,移动图片消除空白部分。

 

Android实现这些操作的两个必不可少的知识就是onTouch事件,Matrix。通过onTouch事件判断你的手势,通过matrix实现图片的拖拽缩放。

onTouch即屏幕触摸事件,必须知道的几个事件:

MotionEvent.ACTION_DOWN:第一根手指按下

MotionEvent.ACTION_POINTER_DOWN:第二根手指按下

MotionEvent.ACTION_UP:第一根手指离开

MotionEvent.ACTION_POINTER_UP:第二根手指离开

MotionEvent.ACTION_MOVE:手指滑动

 

拖拽效果的实现:通过MotionEvent.ACTION_DOWN获得第一根手指按下的坐标A,通过MotionEvent.ACTION_MOVE获得滑动后的坐标B,于是便有了A到B的一个偏移,通过这个偏移完成拖拽效果。

缩放效果的实现:通过MotionEvent.ACTION_DOWN获得第一根手指按下的坐标A,通过MotionEvent.ACTION_POINTER_DOWN获得第二根手指按下的坐标B,于是便有了两点间距AB1。通过MotionEvent.ACTION_MOVE会获得新的A,B两点间距AB2。通过AB2/AB1的值便得知缩放比例。

Matrix没什么可说的,看看API都明白了。有一点要注意的是matrix.postXXX方法指的是在当前matirx基础上进行相应操作,matrix.setXXX是初始化当前matrix后进行的相应操作。

实现代码:

XML:

  1. <RelativeLayout xmlns:android="http://schemas./apk/res/android"  
  2.     xmlns:tools="http://schemas./tools"  
  3.     android:layout_width="match_parent"  
  4.     android:layout_height="match_parent"  
  5.     tools:context=".ShowImage" >  
  6.   
  7.     <ImageView  
  8.         android:id="@+id/imgv"  
  9.         android:layout_width="match_parent"  
  10.         android:layout_height="match_parent"  
  11.         android:scaleType="matrix" />  
  12.   
  13. </RelativeLayout>  

android:scaleType="matrix",这句话是重点


JAVA:

  1. package com.example.showimgdemo;  
  2.   
  3. import android.app.Activity;  
  4. import android.graphics.Bitmap;  
  5. import android.graphics.BitmapFactory;  
  6. import android.graphics.Matrix;  
  7. import android.graphics.PointF;  
  8. import android.graphics.RectF;  
  9. import android.os.Bundle;  
  10. import android.view.MotionEvent;  
  11. import android.view.View;  
  12. import android.view.View.OnTouchListener;  
  13. import android.widget.ImageView;  
  14.   
  15. public class ShowImage extends Activity implements OnTouchListener {  
  16.   
  17.     private ImageView imgv;  
  18.   
  19.     private PointF point0 = new PointF();  
  20.     private PointF pointM = new PointF();  
  21.   
  22.     private final float ZOOM_MIN_SPACE = 10f;  
  23.   
  24.     // 设定事件模式  
  25.     private final int NONE = 0;  
  26.     private final int DRAG = 1;  
  27.     private final int ZOOM = 2;  
  28.     private int mode = NONE;  
  29.   
  30.     private Matrix matrix = new Matrix();  
  31.     private Matrix savedMatrix = new Matrix();  
  32.   
  33.     // 获取屏幕分辨率。以480*320为例  
  34.     private int displayHeight = 480;  
  35.     private int displayWidth = 320;  
  36.   
  37.     private float minScale = 1f;  
  38.     private float maxScale = 10f;  
  39.     private float currentScale = 1f;  
  40.     private float oldDist;  
  41.   
  42.     private Bitmap bm;  
  43.     private int imgWidth;  
  44.     private int imgHeight;  
  45.   
  46.     @Override  
  47.     protected void onCreate(Bundle arg0) {  
  48.         super.onCreate(arg0);  
  49.         setContentView(R.layout.show_image);  
  50.         init();  
  51.     }  
  52.   
  53.     private void init() {  
  54.         imgv = (ImageView) findViewById(R.id.imgv);  
  55.         imgv.setOnTouchListener(this);  
  56.   
  57.         bm = BitmapFactory.decodeResource(getResources(),  
  58.                 R.drawable.test2);  
  59.         imgWidth = bm.getWidth();  
  60.         imgHeight = bm.getHeight();  
  61.         imgv.setImageBitmap(bm);  
  62.         minScale = getMinScale();  
  63.         matrix.setScale(minScale, minScale);  
  64.         center();  
  65.         imgv.setImageMatrix(matrix);  
  66.     }  
  67.   
  68.     @Override  
  69.     public boolean onTouch(View v, MotionEvent event) {  
  70.         ImageView imgv = (ImageView) v;  
  71.         switch (event.getAction() & MotionEvent.ACTION_MASK) {  
  72.         case MotionEvent.ACTION_DOWN:  
  73.             savedMatrix.set(matrix);  
  74.             point0.set(event.getX(), event.getY());  
  75.             mode = DRAG;  
  76.             break;  
  77.         case MotionEvent.ACTION_POINTER_DOWN:  
  78.             oldDist = spacing(event);  
  79.             if (oldDist > ZOOM_MIN_SPACE) {  
  80.                 savedMatrix.set(matrix);  
  81.                 setMidPoint(event);  
  82.                 mode = ZOOM;  
  83.             }  
  84.             break;  
  85.         case MotionEvent.ACTION_UP:  
  86.         case MotionEvent.ACTION_POINTER_UP:  
  87.             mode = NONE;  
  88.             break;  
  89.         case MotionEvent.ACTION_MOVE:  
  90.             whenMove(event);  
  91.             break;  
  92.   
  93.         }  
  94.         imgv.setImageMatrix(matrix);  
  95.         checkView();  
  96.         return true;  
  97.     }  
  98.   
  99.     private void whenMove(MotionEvent event) {  
  100.         switch (mode) {  
  101.         case DRAG:  
  102.             matrix.set(savedMatrix);  
  103.             matrix.postTranslate(event.getX() - point0.x, event.getY()  
  104.                     - point0.y);  
  105.             break;  
  106.         case ZOOM:  
  107.             float newDist = spacing(event);  
  108.             if (newDist > ZOOM_MIN_SPACE) {  
  109.                 matrix.set(savedMatrix);  
  110.                 float sxy = newDist / oldDist;  
  111.                 System.out.println(sxy + "<==放大缩小倍数");  
  112.                 matrix.postScale(sxy, sxy, pointM.x, pointM.y);  
  113.             }  
  114.             break;  
  115.         }  
  116.     }  
  117.   
  118.     // 两个触点的距离  
  119.     private float spacing(MotionEvent event) {  
  120.         float x = event.getX(0) - event.getX(1);  
  121.         float y = event.getY(0) - event.getY(1);  
  122.         return (float) Math.sqrt(x * x + y * y);  
  123.     }  
  124.   
  125.     private void setMidPoint(MotionEvent event) {  
  126.         float x = event.getX(0) + event.getY(1);  
  127.         float y = event.getY(0) + event.getY(1);  
  128.         pointM.set(x / 2, y / 2);  
  129.     }  
  130.   
  131.     // 图片居中  
  132.     private void center() {  
  133.         RectF rect = new RectF(0, 0, imgWidth, imgHeight);  
  134.         matrix.mapRect(rect);  
  135.         float width = rect.width();  
  136.         float height = rect.height();  
  137.         float dx = 0;  
  138.         float dy = 0;  
  139.   
  140.         if (width < displayWidth)  
  141.             dx = displayWidth / 2 - width / 2 - rect.left;  
  142.         else if (rect.left > 0)  
  143.             dx = -rect.left;  
  144.         else if (rect.right < displayWidth)  
  145.             dx = displayWidth - rect.right;  
  146.   
  147.         if (height < displayHeight)  
  148.             dy = displayHeight / 2 - height / 2 - rect.top;  
  149.         else if (rect.top > 0)  
  150.             dy = -rect.top;  
  151.         else if (rect.bottom < displayHeight)  
  152.             dy = displayHeight - rect.bottom;  
  153.   
  154.         matrix.postTranslate(dx, dy);  
  155.     }  
  156.   
  157.     // 获取最小缩放比例  
  158.     private float getMinScale() {  
  159.         float sx = (float) displayWidth / imgWidth;  
  160.         float sy = (float) displayHeight / imgHeight;  
  161.         float scale = sx < sy ? sx : sy;  
  162.         if (scale > 1) {  
  163.             scale = 1f;  
  164.         }  
  165.         return scale;  
  166.     }  
  167.   
  168.     // 检查约束条件,是否居中,空间显示是否合理  
  169.     private void checkView() {  
  170.         currentScale = getCurrentScale();  
  171.         if (mode == ZOOM) {  
  172.             if (currentScale < minScale) {  
  173.                 matrix.setScale(minScale, minScale);  
  174.             }  
  175.             if (currentScale > maxScale) {  
  176.                 matrix.set(savedMatrix);  
  177.             }  
  178.         }  
  179.         center();  
  180.     }  
  181.   
  182.     // 图片当前的缩放比例  
  183.     private float getCurrentScale() {  
  184.         float[] values = new float[9];  
  185.         matrix.getValues(values);  
  186.         return values[Matrix.MSCALE_X];  
  187.     }  
  188. }  


    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多