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

Android   2014-01-24 10:18:38 发布
您的评价:
     
0.0
收藏     2收藏
文件夹
标签
(多个标签用逗号分隔)

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

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

代码如下:
package com.example.test;  
  
import android.content.Context;  
import android.graphics.Bitmap;  
import android.graphics.Canvas;  
import android.graphics.Matrix;  
import android.graphics.PointF;  
import android.graphics.drawable.BitmapDrawable;  
import android.util.AttributeSet;  
import android.util.FloatMath;  
import android.util.Log;  
import android.view.MotionEvent;  
import android.widget.ImageView;  
  
public class TouchImageView extends ImageView {  
  
    private PointF down = new PointF();  
    private PointF mid = new PointF();  
    <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;  
    private Matrix matrix = new Matrix();  
    private Matrix preMatrix = new Matrix();  
    private Matrix savedMatrix = new Matrix();  
  
    private static final int NONE = 0;  
    private static final int DRAG = 1;  
    private static final int ZOOM = 2;  
    private int mode = NONE;  
  
    private boolean isBig = false;  
  
    private int widthScreen;  
    private int heightScreen;  
  
    private int touchImgWidth;  
    private int touchImgHeight;  
  
    private float defaultScale;  
  
    private long lastClickTime = 0;  
  
    private Bitmap touchImg = null;  
  
    private static final int DOUBLE_CLICK_TIME_SPACE = 300;  
    private static final int DOUBLE_POINT_DISTANCE = 10;  
    private static float MAX_SCALE = 3.0f;  
  
    public TouchImageView(Context context) {  
        super(context);  
    }  
  
    public TouchImageView(Context context, AttributeSet attrs) {  
        super(context, attrs);  
    }  
  
    public TouchImageView(Context context, AttributeSet attrs, int defStyleAttr) {  
        super(context, attrs, defStyleAttr);  
    }  
  
    public void initImageView(int screenWidth, int screenHeight) {  
        widthScreen = screenWidth;  
        heightScreen = screenHeight;  
  
        touchImg = ((BitmapDrawable) getDrawable()).getBitmap();  
        touchImgWidth = touchImg.getWidth();  
        touchImgHeight = touchImg.getHeight();  
        float scaleX = (float) widthScreen / touchImgWidth;  
        float scaleY = (float) heightScreen / touchImgHeight;  
        defaultScale = scaleX < scaleY ? scaleX : scaleY;  
  
        float subX = (widthScreen - touchImgWidth * defaultScale) / 2;  
        float subY = (heightScreen - touchImgHeight * defaultScale) / 2;  
        setScaleType(ScaleType.MATRIX);  
        preMatrix.reset();  
        preMatrix.postScale(defaultScale, defaultScale);  
        preMatrix.postTranslate(subX, subY);  
        matrix.set(preMatrix);  
        invalidate();  
    }  
  
    @Override  
    protected void onDraw(Canvas canvas) {  
        if (null != touchImg) {  
            canvas.save();  
            canvas.drawBitmap(touchImg, matrix, null);  
            canvas.restore();  
        }  
    }  
  
    @Override  
    public boolean onTouchEvent(MotionEvent event) {  
        switch (event.getAction() & MotionEvent.ACTION_MASK) {  
        case MotionEvent.ACTION_DOWN:  
            mode = DRAG;  
            down.x = event.getX();  
            down.y = event.getY();  
            savedMatrix.set(matrix);  
  
            if (event.getEventTime() - lastClickTime < DOUBLE_CLICK_TIME_SPACE) {  
                changeSize(event.getX(), event.getY());  
            }  
            lastClickTime = event.getEventTime();  
            break;  
        case MotionEvent.ACTION_POINTER_DOWN:  
            oldDist = spacing(event);  
            if (oldDist > DOUBLE_POINT_DISTANCE) {  
                mode = ZOOM;  
                // oldRotation = rotation(event);  
                savedMatrix.set(matrix);  
                midPoint(mid, event);  
            }  
            break;  
        case MotionEvent.ACTION_MOVE:  
            if (mode == ZOOM) {  
                float newDist = spacing(event);  
                float scale = newDist / oldDist;  
                if (scale > 1.01 || scale < 0.99) {  
                    preMatrix.set(savedMatrix);  
                    preMatrix.postScale(scale, scale, mid.x, mid.y);// 缩放  
                    if (canZoom()) {  
                        matrix.set(preMatrix);  
                        invalidate();  
                    }  
                }  
            } else if (mode == DRAG) {  
                if (1.0f < distance(event, down)) {  
                    preMatrix.set(savedMatrix);  
  
                    preMatrix.postTranslate(event.getX() - down.x, 0);  
                    if (event.getX() > down.x) {  
                        if (canDrag(DRAG_RIGHT)) {  
                            savedMatrix.set(preMatrix);  
                        } else {  
                            preMatrix.set(savedMatrix);  
                        }  
                    } else {  
                        if (canDrag(DRAG_LEFT)) {  
                            savedMatrix.set(preMatrix);  
                        } else {  
                            preMatrix.set(savedMatrix);  
                        }  
                    }  
                    preMatrix.postTranslate(0, event.getY() - down.y);  
                    if (event.getY() > down.y) {  
                        if (canDrag(DRAG_DOWN)) {  
                            savedMatrix.set(preMatrix);  
                        } else {  
                            preMatrix.set(savedMatrix);  
                        }  
                    } else {  
                        if (canDrag(DRAG_TOP)) {  
                            savedMatrix.set(preMatrix);  
                        } else {  
                            preMatrix.set(savedMatrix);  
                        }  
                    }  
  
                    matrix.set(preMatrix);  
                    invalidate();  
                    down.x = event.getX();  
                    down.y = event.getY();  
                    savedMatrix.set(matrix);  
                }  
            }  
            break;  
        case MotionEvent.ACTION_UP:  
            mode = NONE;  
            springback();  
            break;  
        case MotionEvent.ACTION_POINTER_UP:  
            mode = NONE;  
            break;  
        }  
        return true;  
    }  
  
    private void springback() {  
        preMatrix.set(matrix);  
        float[] x = new float[4];  
        float[] y = new float[4];  
        getFourPoint(x, y);  
        if (x[1] - x[0] > widthScreen) {  
            if (x[0] > 0) {  
                preMatrix.postTranslate(-x[0], 0);  
                matrix.set(preMatrix);  
                invalidate();  
            } else if (x[1] < widthScreen) {  
                preMatrix.postTranslate(widthScreen - x[1], 0);  
                matrix.set(preMatrix);  
                invalidate();  
            }  
        } else if (x[1] - x[0] < widthScreen - 1f) {  
            preMatrix.postTranslate((widthScreen - (x[1] - x[0])) / 2 - x[0], 0);  
            matrix.set(preMatrix);  
            invalidate();  
        }  
  
        if (y[2] - y[0] > heightScreen) {  
            if (y[0] > 0) {  
                preMatrix.postTranslate(0, -y[0]);  
                matrix.set(preMatrix);  
                invalidate();  
            } else if (y[2] < heightScreen) {  
                preMatrix.postTranslate(0, heightScreen - y[2]);  
                matrix.set(preMatrix);  
                invalidate();  
            }  
        } else if (y[2] - y[0] < heightScreen - 1f) {  
            preMatrix.postTranslate(0, (heightScreen - (y[2] - y[0])) / 2  
                    - y[0]);  
            matrix.set(preMatrix);  
            invalidate();  
        }  
    }  
  
    private void getFourPoint(float[] x, float[] y) {  
        float[] f = new float[9];  
        preMatrix.getValues(f);  
        // 图片4个顶点的坐标  
        x[0] = f[Matrix.MSCALE_X] * 0 + f[Matrix.MSKEW_X] * 0  
                + f[Matrix.MTRANS_X];  
        y[0] = f[Matrix.MSKEW_Y] * 0 + f[Matrix.MSCALE_Y] * 0  
                + f[Matrix.MTRANS_Y];  
        x[1] = f[Matrix.MSCALE_X] * touchImg.getWidth() + f[Matrix.MSKEW_X] * 0  
                + f[Matrix.MTRANS_X];  
        y[1] = f[Matrix.MSKEW_Y] * touchImg.getWidth() + f[Matrix.MSCALE_Y] * 0  
                + f[Matrix.MTRANS_Y];  
        x[2] = f[Matrix.MSCALE_X] * 0 + f[Matrix.MSKEW_X]  
                * touchImg.getHeight() + f[Matrix.MTRANS_X];  
        y[2] = f[Matrix.MSKEW_Y] * 0 + f[Matrix.MSCALE_Y]  
                * touchImg.getHeight() + f[Matrix.MTRANS_Y];  
        x[3] = f[Matrix.MSCALE_X] * touchImg.getWidth() + f[Matrix.MSKEW_X]  
                * touchImg.getHeight() + f[Matrix.MTRANS_X];  
        y[3] = f[Matrix.MSKEW_Y] * touchImg.getWidth() + f[Matrix.MSCALE_Y]  
                * touchImg.getHeight() + f[Matrix.MTRANS_Y];  
    }  
  
    private final static int DRAG_LEFT = 0;  
    private final static int DRAG_RIGHT = 1;  
    private final static int DRAG_TOP = 2;  
    private final static int DRAG_DOWN = 3;  
  
    private boolean canDrag(final int direction) {  
        float[] x = new float[4];  
        float[] y = new float[4];  
        getFourPoint(x, y);  
  
        // 出界判断  
        if ((x[0] > 0 || x[2] > 0 || x[1] < widthScreen || x[3] < widthScreen)  
                && (y[0] > 0 || y[1] > 0 || y[2] < heightScreen || y[3] < heightScreen)) {  
            return false;  
        }  
        if (DRAG_LEFT == direction) {  
            // 左移出界判断  
            if (x[1] < widthScreen || x[3] < widthScreen) {  
                return false;  
            }  
        } else if (DRAG_RIGHT == direction) {  
            // 右移出界判断  
            if (x[0] > 0 || x[2] > 0) {  
                return false;  
            }  
        } else if (DRAG_TOP == direction) {  
            // 上移出界判断  
            if (y[2] < heightScreen || y[3] < heightScreen) {  
                return false;  
            }  
        } else if (DRAG_DOWN == direction) {  
            // 下移出界判断  
            if (y[0] > 0 || y[1] > 0) {  
                return false;  
            }  
        } else {  
            return false;  
        }  
        return true;  
    }  
  
    private boolean canZoom() {  
        float[] x = new float[4];  
        float[] y = new float[4];  
        getFourPoint(x, y);  
        // 图片现宽度  
        double width = Math.sqrt((x[0] - x[1]) * (x[0] - x[1]) + (y[0] - y[1])  
                * (y[0] - y[1]));  
        double height = Math.sqrt((x[0] - x[2]) * (x[0] - x[2]) + (y[0] - y[2])  
                * (y[0] - y[2]));  
        // 缩放比率判断  
        if (width < touchImgWidth * defaultScale - 1  
                || width > touchImgWidth * MAX_SCALE + 1) {  
            return false;  
        }  
  
        // 出界判断  
        if (width < widthScreen && height < heightScreen) {  
            return false;  
        }  
        return true;  
    }  
  
    // 触碰两点间距离  
    private static float spacing(MotionEvent event) {  
        float x = event.getX(0) - event.getX(1);  
        if (x < 0) {  
            x = -x;  
        }  
        float y = event.getY(0) - event.getY(1);  
        if (y < 0) {  
            y = -y;  
        }  
        return FloatMath.sqrt(x * x + y * y);  
    }  
  
    // 取手势中心点  
    private static 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 static float distance(MotionEvent point2, PointF point1) {  
        float x = point1.x - point2.getX();  
        if (x < 0) {  
            x = -x;  
        }  
        float y = point1.y - point2.getY();  
        if (y < 0) {  
            y = -y;  
        }  
        return FloatMath.sqrt(x * x + y * y);  
    }  
  
    private void changeSize(float x, float y) {  
        if (isBig) {  
            float subX = (widthScreen - touchImgWidth * defaultScale) / 2;  
            float subY = (heightScreen - touchImgHeight * defaultScale) / 2;  
            preMatrix.reset();  
            preMatrix.postScale(defaultScale, defaultScale);  
            preMatrix.postTranslate(subX, subY);  
            matrix.set(preMatrix);  
            invalidate();  
  
            isBig = false;  
        } else {  
            float transX = (widthScreen - touchImgWidth * MAX_SCALE) / 2;  
            float transY = (heightScreen - touchImgHeight * MAX_SCALE) / 2;  
            preMatrix.reset();  
            preMatrix.postScale(MAX_SCALE, MAX_SCALE);  
            preMatrix.postTranslate(transX, transY);  
            matrix.set(preMatrix);  
            invalidate();  
  
            isBig = true;  
        }  
    }  
}  
</pre>  
<pre></pre>  
<pre></pre>  
<p></p>  
<pre></pre>  
<pre></pre>  
<p><br>  
</p>  
<p><br>  
</p>  
<p></p>  
<p>测试代码如下:</p>  
<p><br>  
</p>  
<p>activity_main.xml文件:</p>  
<p></p>  
<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"  
    xmlns:tools="http://schemas.android.com/tools"  
    android:id="@+id/layout_id"  
    android:layout_width="match_parent"  
    android:layout_height="match_parent"  
    tools:context=".MainActivity" >  
  
    <com.example.test.TouchImageView  
        android:id="@+id/img_id"  
        android:layout_width="400dip"  
        android:layout_height="800dip"  
        android:src="@drawable/banner"  
        android:scaleType="fitCenter" />  
  
</LinearLayout>  
</pre><br>  
<p><br>  
</p>  
<p>MainActivity.java文件:</p>  
<p></p>  
<p></p>  
<pre code_snippet_id="168679" snippet_file_name="blog_20140123_3_2367928" name="code" class="java">package com.example.test;  
  
import android.app.Activity;  
import android.os.Bundle;  
import android.util.DisplayMetrics;  
import android.view.Menu;  
import android.view.ViewTreeObserver.OnGlobalLayoutListener;  
import android.widget.LinearLayout;  
  
public class MainActivity extends Activity {  
  
    private TouchImageView imgView;  
  
    @Override  
    protected void onCreate(Bundle savedInstanceState) {  
        super.onCreate(savedInstanceState);  
        setContentView(R.layout.activity_main);  
  
        DisplayMetrics dm = new DisplayMetrics();  
        getWindowManager().getDefaultDisplay().getMetrics(dm);  
  
        TouchImageView imgView = (TouchImageView) findViewById(R.id.img_id);  
        imgView.initImageView(dm.widthPixels, dm.heightPixels - 80);  
    }  
  
    @Override  
    public boolean onCreateOptionsMenu(Menu menu) {  
        // Inflate the menu; this adds items to the action bar if it is present.  
        getMenuInflater().inflate(R.menu.main, menu);  
        return true;  
    }  
  
}  

扩展阅读

GitHub 优秀的 Android 开源项目
4.0)全面整理 href="/lib/view/open1385211570119.html">Android 各版本历史主要变动(Version1.5-->4.0)全面整理
GitHub上最火的74个Android开源项目(三)
Android开源项目分类汇总
Android常用开源项目

为您推荐

android酷炫翻页效果+图形分析
Android多点触控
通过手势实现Android ImageView 缩放
Android之关于手势操作图片的缩放与移动
Android图片查看器(图片可移动、缩放、旋转)

更多

Android
Android开发
相关文档  — 更多
相关经验  — 更多
相关讨论  — 更多