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

大多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.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/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];
	}
}


  • 0
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值