大多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:
- <RelativeLayout xmlns:android="http://schemas./apk/res/android"
- xmlns:tools="http://schemas./tools"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- tools:context=".ShowImage" >
-
- <ImageView
- android:id="@+id/imgv"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:scaleType="matrix" />
-
- </RelativeLayout>
android:scaleType="matrix",这句话是重点
JAVA:
- package com.example.showimgdemo;
-
- import android.app.Activity;
- import android.graphics.Bitmap;
- import android.graphics.BitmapFactory;
- import android.graphics.Matrix;
- import android.graphics.PointF;
- import android.graphics.RectF;
- import android.os.Bundle;
- import android.view.MotionEvent;
- import android.view.View;
- import android.view.View.OnTouchListener;
- import android.widget.ImageView;
-
- public class ShowImage extends Activity implements OnTouchListener {
-
- private ImageView imgv;
-
- private PointF point0 = new PointF();
- private PointF pointM = new PointF();
-
- private final float ZOOM_MIN_SPACE = 10f;
-
- // 设定事件模式
- private final int NONE = 0;
- private final int DRAG = 1;
- private final int ZOOM = 2;
- private int mode = NONE;
-
- private Matrix matrix = new Matrix();
- private Matrix savedMatrix = new Matrix();
-
- // 获取屏幕分辨率。以480*320为例
- private int displayHeight = 480;
- private int displayWidth = 320;
-
- private float minScale = 1f;
- private float maxScale = 10f;
- private float currentScale = 1f;
- private float oldDist;
-
- private Bitmap bm;
- private int imgWidth;
- private int imgHeight;
-
- @Override
- protected void onCreate(Bundle arg0) {
- super.onCreate(arg0);
- setContentView(R.layout.show_image);
- init();
- }
-
- private void init() {
- imgv = (ImageView) findViewById(R.id.imgv);
- imgv.setOnTouchListener(this);
-
- bm = BitmapFactory.decodeResource(getResources(),
- R.drawable.test2);
- imgWidth = bm.getWidth();
- imgHeight = bm.getHeight();
- imgv.setImageBitmap(bm);
- minScale = getMinScale();
- matrix.setScale(minScale, minScale);
- center();
- imgv.setImageMatrix(matrix);
- }
-
- @Override
- public boolean onTouch(View v, MotionEvent event) {
- ImageView imgv = (ImageView) v;
- switch (event.getAction() & MotionEvent.ACTION_MASK) {
- case MotionEvent.ACTION_DOWN:
- savedMatrix.set(matrix);
- point0.set(event.getX(), event.getY());
- mode = DRAG;
- break;
- case MotionEvent.ACTION_POINTER_DOWN:
- oldDist = spacing(event);
- if (oldDist > ZOOM_MIN_SPACE) {
- savedMatrix.set(matrix);
- setMidPoint(event);
- mode = ZOOM;
- }
- break;
- case MotionEvent.ACTION_UP:
- case MotionEvent.ACTION_POINTER_UP:
- mode = NONE;
- break;
- case MotionEvent.ACTION_MOVE:
- whenMove(event);
- break;
-
- }
- imgv.setImageMatrix(matrix);
- checkView();
- return true;
- }
-
- private void whenMove(MotionEvent event) {
- switch (mode) {
- case DRAG:
- matrix.set(savedMatrix);
- matrix.postTranslate(event.getX() - point0.x, event.getY()
- - point0.y);
- break;
- case ZOOM:
- float newDist = spacing(event);
- if (newDist > ZOOM_MIN_SPACE) {
- matrix.set(savedMatrix);
- float sxy = newDist / oldDist;
- System.out.println(sxy + "<==放大缩小倍数");
- matrix.postScale(sxy, sxy, pointM.x, pointM.y);
- }
- break;
- }
- }
-
- // 两个触点的距离
- 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 setMidPoint(MotionEvent event) {
- float x = event.getX(0) + event.getY(1);
- float y = event.getY(0) + event.getY(1);
- pointM.set(x / 2, y / 2);
- }
-
- // 图片居中
- private void center() {
- RectF rect = new RectF(0, 0, imgWidth, imgHeight);
- matrix.mapRect(rect);
- float width = rect.width();
- float height = rect.height();
- float dx = 0;
- float dy = 0;
-
- if (width < displayWidth)
- dx = displayWidth / 2 - width / 2 - rect.left;
- else if (rect.left > 0)
- dx = -rect.left;
- else if (rect.right < displayWidth)
- dx = displayWidth - rect.right;
-
- if (height < displayHeight)
- dy = displayHeight / 2 - height / 2 - rect.top;
- else if (rect.top > 0)
- dy = -rect.top;
- else if (rect.bottom < displayHeight)
- dy = displayHeight - rect.bottom;
-
- matrix.postTranslate(dx, dy);
- }
-
- // 获取最小缩放比例
- private float getMinScale() {
- float sx = (float) displayWidth / imgWidth;
- float sy = (float) displayHeight / imgHeight;
- float scale = sx < sy ? sx : sy;
- if (scale > 1) {
- scale = 1f;
- }
- return scale;
- }
-
- // 检查约束条件,是否居中,空间显示是否合理
- private void checkView() {
- currentScale = getCurrentScale();
- if (mode == ZOOM) {
- if (currentScale < minScale) {
- matrix.setScale(minScale, minScale);
- }
- if (currentScale > maxScale) {
- matrix.set(savedMatrix);
- }
- }
- center();
- }
-
- // 图片当前的缩放比例
- private float getCurrentScale() {
- float[] values = new float[9];
- matrix.getValues(values);
- return values[Matrix.MSCALE_X];
- }
- }
|