Android单张图片查看、单指移动、双指缩放、双击最大化或最小化

转:http://blog.csdn.net/huyiyang2010/article/details/18712997转: 

Android单张图片查看、单指移动、双指缩放、双击最大化或最小化

标签: android图片移动imageviewbitmap
  4308人阅读  评论(6)  收藏  举报
  分类:

Android平台上查看单张图片时,通常情况下需要实现图片查看、单指移动、双指缩放、双击最大化或最小化功能。

目前网络上的实现方式,都没有将此功能封装为类,零落在类和xml文件中,代码难以阅读,功能难以复用。

为此,我专门写了一个类做此功能。此类唯一的缺点是没有实现回弹动画。不说废话了,上代码。

代码如下:

[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. package com.example.test;  
  2.   
  3. import android.content.Context;  
  4. import android.graphics.Bitmap;  
  5. import android.graphics.Canvas;  
  6. import android.graphics.Matrix;  
  7. import android.graphics.PointF;  
  8. import android.graphics.drawable.BitmapDrawable;  
  9. import android.util.AttributeSet;  
  10. import android.util.FloatMath;  
  11. import android.util.Log;  
  12. import android.view.MotionEvent;  
  13. import android.widget.ImageView;  
  14.   
  15. public class TouchImageView extends ImageView {  
  16.   
  17.     private PointF down = new PointF();  
  18.     private PointF mid = new PointF();  
  19.     <pre code_snippet_id="168679" snippet_file_name="blog_20140123_1_7635608" name="code" class="java"><pre code_snippet_id="168679" snippet_file_name="blog_20140123_1_7635608" name="code" class="java">  private float oldDist = 1f;  
  20.     private Matrix matrix = new Matrix();  
  21.     private Matrix preMatrix = new Matrix();  
  22.     private Matrix savedMatrix = new Matrix();  
  23.   
  24.     private static final int NONE = 0;  
  25.     private static final int DRAG = 1;  
  26.     private static final int ZOOM = 2;  
  27.     private int mode = NONE;  
  28.   
  29.     private boolean isBig = false;  
  30.   
  31.     private int widthScreen;  
  32.     private int heightScreen;  
  33.   
  34.     private int touchImgWidth;  
  35.     private int touchImgHeight;  
  36.   
  37.     private float defaultScale;  
  38.   
  39.     private long lastClickTime = 0;  
  40.   
  41.     private Bitmap touchImg = null;  
  42.   
  43.     private static final int DOUBLE_CLICK_TIME_SPACE = 300;  
  44.     private static final int DOUBLE_POINT_DISTANCE = 10;  
  45.     private static float MAX_SCALE = 3.0f;  
  46.   
  47.     public TouchImageView(Context context) {  
  48.         super(context);  
  49.     }  
  50.   
  51.     public TouchImageView(Context context, AttributeSet attrs) {  
  52.         super(context, attrs);  
  53.     }  
  54.   
  55.     public TouchImageView(Context context, AttributeSet attrs, int defStyleAttr) {  
  56.         super(context, attrs, defStyleAttr);  
  57.     }  
  58.   
  59.     public void initImageView(int screenWidth, int screenHeight) {  
  60.         widthScreen = screenWidth;  
  61.         heightScreen = screenHeight;  
  62.   
  63.         touchImg = ((BitmapDrawable) getDrawable()).getBitmap();  
  64.         touchImgWidth = touchImg.getWidth();  
  65.         touchImgHeight = touchImg.getHeight();  
  66.         float scaleX = (float) widthScreen / touchImgWidth;  
  67.         float scaleY = (float) heightScreen / touchImgHeight;  
  68.         defaultScale = scaleX < scaleY ? scaleX : scaleY;  
  69.   
  70.         float subX = (widthScreen - touchImgWidth * defaultScale) / 2;  
  71.         float subY = (heightScreen - touchImgHeight * defaultScale) / 2;  
  72.         setScaleType(ScaleType.MATRIX);  
  73.         preMatrix.reset();  
  74.         preMatrix.postScale(defaultScale, defaultScale);  
  75.         preMatrix.postTranslate(subX, subY);  
  76.         matrix.set(preMatrix);  
  77.         invalidate();  
  78.     }  
  79.   
  80.     @Override  
  81.     protected void onDraw(Canvas canvas) {  
  82.         if (null != touchImg) {  
  83.             canvas.save();  
  84.             canvas.drawBitmap(touchImg, matrix, null);  
  85.             canvas.restore();  
  86.         }  
  87.     }  
  88.   
  89.     @Override  
  90.     public boolean onTouchEvent(MotionEvent event) {  
  91.         switch (event.getAction() & MotionEvent.ACTION_MASK) {  
  92.         case MotionEvent.ACTION_DOWN:  
  93.             mode = DRAG;  
  94.             down.x = event.getX();  
  95.             down.y = event.getY();  
  96.             savedMatrix.set(matrix);  
  97.   
  98.             if (event.getEventTime() - lastClickTime < DOUBLE_CLICK_TIME_SPACE) {  
  99.                 changeSize(event.getX(), event.getY());  
  100.             }  
  101.             lastClickTime = event.getEventTime();  
  102.             break;  
  103.         case MotionEvent.ACTION_POINTER_DOWN:  
  104.             oldDist = spacing(event);  
  105.             if (oldDist > DOUBLE_POINT_DISTANCE) {  
  106.                 mode = ZOOM;  
  107.                 // oldRotation = rotation(event);  
  108.                 savedMatrix.set(matrix);  
  109.                 midPoint(mid, event);  
  110.             }  
  111.             break;  
  112.         case MotionEvent.ACTION_MOVE:  
  113.             if (mode == ZOOM) {  
  114.                 float newDist = spacing(event);  
  115.                 float scale = newDist / oldDist;  
  116.                 if (scale > 1.01 || scale < 0.99) {  
  117.                     preMatrix.set(savedMatrix);  
  118.                     preMatrix.postScale(scale, scale, mid.x, mid.y);// 缩放  
  119.                     if (canZoom()) {  
  120.                         matrix.set(preMatrix);  
  121.                         invalidate();  
  122.                     }  
  123.                 }  
  124.             } else if (mode == DRAG) {  
  125.                 if (1.0f < distance(event, down)) {  
  126.                     preMatrix.set(savedMatrix);  
  127.   
  128.                     preMatrix.postTranslate(event.getX() - down.x, 0);  
  129.                     if (event.getX() > down.x) {  
  130.                         if (canDrag(DRAG_RIGHT)) {  
  131.                             savedMatrix.set(preMatrix);  
  132.                         } else {  
  133.                             preMatrix.set(savedMatrix);  
  134.                         }  
  135.                     } else {  
  136.                         if (canDrag(DRAG_LEFT)) {  
  137.                             savedMatrix.set(preMatrix);  
  138.                         } else {  
  139.                             preMatrix.set(savedMatrix);  
  140.                         }  
  141.                     }  
  142.                     preMatrix.postTranslate(0, event.getY() - down.y);  
  143.                     if (event.getY() > down.y) {  
  144.                         if (canDrag(DRAG_DOWN)) {  
  145.                             savedMatrix.set(preMatrix);  
  146.                         } else {  
  147.                             preMatrix.set(savedMatrix);  
  148.                         }  
  149.                     } else {  
  150.                         if (canDrag(DRAG_TOP)) {  
  151.                             savedMatrix.set(preMatrix);  
  152.                         } else {  
  153.                             preMatrix.set(savedMatrix);  
  154.                         }  
  155.                     }  
  156.   
  157.                     matrix.set(preMatrix);  
  158.                     invalidate();  
  159.                     down.x = event.getX();  
  160.                     down.y = event.getY();  
  161.                     savedMatrix.set(matrix);  
  162.                 }  
  163.             }  
  164.             break;  
  165.         case MotionEvent.ACTION_UP:  
  166.             mode = NONE;  
  167.             springback();  
  168.             break;  
  169.         case MotionEvent.ACTION_POINTER_UP:  
  170.             mode = NONE;  
  171.             break;  
  172.         }  
  173.         return true;  
  174.     }  
  175.   
  176.     private void springback() {  
  177.         preMatrix.set(matrix);  
  178.         float[] x = new float[4];  
  179.         float[] y = new float[4];  
  180.         getFourPoint(x, y);  
  181.         if (x[1] - x[0] > widthScreen) {  
  182.             if (x[0] > 0) {  
  183.                 preMatrix.postTranslate(-x[0], 0);  
  184.                 matrix.set(preMatrix);  
  185.                 invalidate();  
  186.             } else if (x[1] < widthScreen) {  
  187.                 preMatrix.postTranslate(widthScreen - x[1], 0);  
  188.                 matrix.set(preMatrix);  
  189.                 invalidate();  
  190.             }  
  191.         } else if (x[1] - x[0] < widthScreen - 1f) {  
  192.             preMatrix.postTranslate((widthScreen - (x[1] - x[0])) / 2 - x[0], 0);  
  193.             matrix.set(preMatrix);  
  194.             invalidate();  
  195.         }  
  196.   
  197.         if (y[2] - y[0] > heightScreen) {  
  198.             if (y[0] > 0) {  
  199.                 preMatrix.postTranslate(0, -y[0]);  
  200.                 matrix.set(preMatrix);  
  201.                 invalidate();  
  202.             } else if (y[2] < heightScreen) {  
  203.                 preMatrix.postTranslate(0, heightScreen - y[2]);  
  204.                 matrix.set(preMatrix);  
  205.                 invalidate();  
  206.             }  
  207.         } else if (y[2] - y[0] < heightScreen - 1f) {  
  208.             preMatrix.postTranslate(0, (heightScreen - (y[2] - y[0])) / 2  
  209.                     - y[0]);  
  210.             matrix.set(preMatrix);  
  211.             invalidate();  
  212.         }  
  213.     }  
  214.   
  215.     private void getFourPoint(float[] x, float[] y) {  
  216.         float[] f = new float[9];  
  217.         preMatrix.getValues(f);  
  218.         // 图片4个顶点的坐标  
  219.         x[0] = f[Matrix.MSCALE_X] * 0 + f[Matrix.MSKEW_X] * 0  
  220.                 + f[Matrix.MTRANS_X];  
  221.         y[0] = f[Matrix.MSKEW_Y] * 0 + f[Matrix.MSCALE_Y] * 0  
  222.                 + f[Matrix.MTRANS_Y];  
  223.         x[1] = f[Matrix.MSCALE_X] * touchImg.getWidth() + f[Matrix.MSKEW_X] * 0  
  224.                 + f[Matrix.MTRANS_X];  
  225.         y[1] = f[Matrix.MSKEW_Y] * touchImg.getWidth() + f[Matrix.MSCALE_Y] * 0  
  226.                 + f[Matrix.MTRANS_Y];  
  227.         x[2] = f[Matrix.MSCALE_X] * 0 + f[Matrix.MSKEW_X]  
  228.                 * touchImg.getHeight() + f[Matrix.MTRANS_X];  
  229.         y[2] = f[Matrix.MSKEW_Y] * 0 + f[Matrix.MSCALE_Y]  
  230.                 * touchImg.getHeight() + f[Matrix.MTRANS_Y];  
  231.         x[3] = f[Matrix.MSCALE_X] * touchImg.getWidth() + f[Matrix.MSKEW_X]  
  232.                 * touchImg.getHeight() + f[Matrix.MTRANS_X];  
  233.         y[3] = f[Matrix.MSKEW_Y] * touchImg.getWidth() + f[Matrix.MSCALE_Y]  
  234.                 * touchImg.getHeight() + f[Matrix.MTRANS_Y];  
  235.     }  
  236.   
  237.     private final static int DRAG_LEFT = 0;  
  238.     private final static int DRAG_RIGHT = 1;  
  239.     private final static int DRAG_TOP = 2;  
  240.     private final static int DRAG_DOWN = 3;  
  241.   
  242.     private boolean canDrag(final int direction) {  
  243.         float[] x = new float[4];  
  244.         float[] y = new float[4];  
  245.         getFourPoint(x, y);  
  246.   
  247.         // 出界判断  
  248.         if ((x[0] > 0 || x[2] > 0 || x[1] < widthScreen || x[3] < widthScreen)  
  249.                 && (y[0] > 0 || y[1] > 0 || y[2] < heightScreen || y[3] < heightScreen)) {  
  250.             return false;  
  251.         }  
  252.         if (DRAG_LEFT == direction) {  
  253.             // 左移出界判断  
  254.             if (x[1] < widthScreen || x[3] < widthScreen) {  
  255.                 return false;  
  256.             }  
  257.         } else if (DRAG_RIGHT == direction) {  
  258.             // 右移出界判断  
  259.             if (x[0] > 0 || x[2] > 0) {  
  260.                 return false;  
  261.             }  
  262.         } else if (DRAG_TOP == direction) {  
  263.             // 上移出界判断  
  264.             if (y[2] < heightScreen || y[3] < heightScreen) {  
  265.                 return false;  
  266.             }  
  267.         } else if (DRAG_DOWN == direction) {  
  268.             // 下移出界判断  
  269.             if (y[0] > 0 || y[1] > 0) {  
  270.                 return false;  
  271.             }  
  272.         } else {  
  273.             return false;  
  274.         }  
  275.         return true;  
  276.     }  
  277.   
  278.     private boolean canZoom() {  
  279.         float[] x = new float[4];  
  280.         float[] y = new float[4];  
  281.         getFourPoint(x, y);  
  282.         // 图片现宽度  
  283.         double width = Math.sqrt((x[0] - x[1]) * (x[0] - x[1]) + (y[0] - y[1])  
  284.                 * (y[0] - y[1]));  
  285.         double height = Math.sqrt((x[0] - x[2]) * (x[0] - x[2]) + (y[0] - y[2])  
  286.                 * (y[0] - y[2]));  
  287.         // 缩放比率判断  
  288.         if (width < touchImgWidth * defaultScale - 1  
  289.                 || width > touchImgWidth * MAX_SCALE + 1) {  
  290.             return false;  
  291.         }  
  292.   
  293.         // 出界判断  
  294.         if (width < widthScreen && height < heightScreen) {  
  295.             return false;  
  296.         }  
  297.         return true;  
  298.     }  
  299.   
  300.     // 触碰两点间距离  
  301.     private static float spacing(MotionEvent event) {  
  302.         float x = event.getX(0) - event.getX(1);  
  303.         if (x < 0) {  
  304.             x = -x;  
  305.         }  
  306.         float y = event.getY(0) - event.getY(1);  
  307.         if (y < 0) {  
  308.             y = -y;  
  309.         }  
  310.         return FloatMath.sqrt(x * x + y * y);  
  311.     }  
  312.   
  313.     // 取手势中心点  
  314.     private static void midPoint(PointF point, MotionEvent event) {  
  315.         float x = event.getX(0) + event.getX(1);  
  316.         float y = event.getY(0) + event.getY(1);  
  317.         point.set(x / 2, y / 2);  
  318.     }  
  319.   
  320.     // 取两点之间的距离  
  321.     private static float distance(MotionEvent point2, PointF point1) {  
  322.         float x = point1.x - point2.getX();  
  323.         if (x < 0) {  
  324.             x = -x;  
  325.         }  
  326.         float y = point1.y - point2.getY();  
  327.         if (y < 0) {  
  328.             y = -y;  
  329.         }  
  330.         return FloatMath.sqrt(x * x + y * y);  
  331.     }  
  332.   
  333.     private void changeSize(float x, float y) {  
  334.         if (isBig) {  
  335.             float subX = (widthScreen - touchImgWidth * defaultScale) / 2;  
  336.             float subY = (heightScreen - touchImgHeight * defaultScale) / 2;  
  337.             preMatrix.reset();  
  338.             preMatrix.postScale(defaultScale, defaultScale);  
  339.             preMatrix.postTranslate(subX, subY);  
  340.             matrix.set(preMatrix);  
  341.             invalidate();  
  342.   
  343.             isBig = false;  
  344.         } else {  
  345.             float transX = (widthScreen - touchImgWidth * MAX_SCALE) / 2;  
  346.             float transY = (heightScreen - touchImgHeight * MAX_SCALE) / 2;  
  347.             preMatrix.reset();  
  348.             preMatrix.postScale(MAX_SCALE, MAX_SCALE);  
  349.             preMatrix.postTranslate(transX, transY);  
  350.             matrix.set(preMatrix);  
  351.             invalidate();  
  352.   
  353.             isBig = true;  
  354.         }  
  355.     }  
  356. }  
  357. </pre>  
  358. <pre></pre>  
  359. <pre></pre>  
  360. <p></p>  
  361. <pre></pre>  
  362. <pre></pre>  
  363. <p><br>  
  364. </p>  
  365. <p><br>  
  366. </p>  
  367. <p></p>  
  368. <p>测试代码如下:</p>  
  369. <p><br>  
  370. </p>  
  371. <p>activity_main.xml文件:</p>  
  372. <p></p>  
  373. <pre code_snippet_id="168679" snippet_file_name="blog_20140123_2_8257273" name="code" class="html"><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  
  374.     xmlns:tools="http://schemas.android.com/tools"  
  375.     android:id="@+id/layout_id"  
  376.     android:layout_width="match_parent"  
  377.     android:layout_height="match_parent"  
  378.     tools:context=".MainActivity" >  
  379.   
  380.     <com.example.test.TouchImageView  
  381.         android:id="@+id/img_id"  
  382.         android:layout_width="400dip"  
  383.         android:layout_height="800dip"  
  384.         android:src="@drawable/banner"  
  385.         android:scaleType="fitCenter" />  
  386.   
  387. </LinearLayout>  
  388. </pre><br>  
  389. <p><br>  
  390. </p>  
  391. <p>MainActivity.java文件:</p>  
  392. <p></p>  
  393. <p></p>  
  394. <pre code_snippet_id="168679" snippet_file_name="blog_20140123_3_2367928" name="code" class="java">package com.example.test;  
  395.   
  396. import android.app.Activity;  
  397. import android.os.Bundle;  
  398. import android.util.DisplayMetrics;  
  399. import android.view.Menu;  
  400. import android.view.ViewTreeObserver.OnGlobalLayoutListener;  
  401. import android.widget.LinearLayout;  
  402.   
  403. public class MainActivity extends Activity {  
  404.   
  405.     private TouchImageView imgView;  
  406.   
  407.     @Override  
  408.     protected void onCreate(Bundle savedInstanceState) {  
  409.         super.onCreate(savedInstanceState);  
  410.         setContentView(R.layout.activity_main);  
  411.   
  412.         DisplayMetrics dm = new DisplayMetrics();  
  413.         getWindowManager().getDefaultDisplay().getMetrics(dm);  
  414.   
  415.         TouchImageView imgView = (TouchImageView) findViewById(R.id.img_id);  
  416.         imgView.initImageView(dm.widthPixels, dm.heightPixels - 80);  
  417.     }  
  418.   
  419.     @Override  
  420.     public boolean onCreateOptionsMenu(Menu menu) {  
  421.         // Inflate the menu; this adds items to the action bar if it is present.  
  422.         getMenuInflater().inflate(R.menu.main, menu);  
  423.         return true;  
  424.     }  
  425.   
  426. }  
  427. </pre><br>  
  428. <br>  
  429. <p></p>  
  430.      
  431. </pre>  
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值