android pinch:双指缩放图片和单指拖拽

袁赞
2023-12-01

当时百度的。实在没记住出处。效果很理想,就收藏了。

package com.demo.pinch;

import android.content.Context;
import android.graphics.Bitmap;
import android.util.FloatMath;
import android.view.MotionEvent;
import android.view.animation.AccelerateInterpolator;
import android.view.animation.Animation;
import android.view.animation.Animation.AnimationListener;
import android.view.animation.ScaleAnimation;
import android.view.animation.TranslateAnimation;
import android.widget.ImageView;

/**
 * ImageView Tonuch
 * 
 * @author Laladin.SYD
 * 
 */
public class PinchableImageView extends ImageView {
	static final int NONE = 0;
	// 拖动中
	static final int DRAG = 1;
	// 缩放中
	static final int ZOOM = 2;
	// 放大ing
	static final int BIGGER = 3;
	// 缩小ing
	static final int SMALLER = 4;
	// 关闭缩放动画
	static final int OPENSCALE = 1;
	// 关闭移动动画
	static final int OPENTRANS = 2;
	// 当前的事件
	private int mode = NONE;
	// 两触点距离
	private float beforeLenght;
	// 两触点距离
	private float afterLenght;
	// 缩放的比例 X Y方向都是这个值 越大缩放的越快
	private float scale = 0.06f;
	/* 处理拖动 变量 */
	private int screenW;
	private int screenH;
	private int start_x;
	private int start_y;
	private int stop_x;
	private int stop_y;
	private TranslateAnimation trans;
	/* Bitmap的宽高 */
	private int bmWidth;
	private int bmHeight;
	// 处理超出边界的动画
	private Bitmap bitmap;
	private float maxScale = 2.0f;
	private float minScale = 1.0f;
	// 记录初始宽度,用于缩放回弹
	private int startWidth = 0;
	private float piovtX = 0.5f;
	private float piovtY = 0.5f;
	// 默认开启所有动画
	private int AnimSwitch = OPENSCALE | OPENTRANS;

	/**
	 * 构造函数
	 * 
	 * @param context
	 *            相关上下文
	 * @param w
	 *            容器的宽
	 * @param h
	 *            容器的高
	 */
	public PinchableImageView(Context context, int w, int h) {
		super(context);
		this.setPadding(0, 0, 0, 0);
		screenW = w;
		screenH = h;
	}

	@Override
	public void setImageBitmap(Bitmap bm) {
		super.setImageBitmap(bm);
		// 重置startWidth
		startWidth = 0;
		bmWidth = bm.getWidth();
		bmHeight = bm.getHeight();
		if (bitmap != null && !bitmap.isRecycled())
			bitmap.recycle();
		bitmap = bm;
	}

	/**
	 * 释放ImageView的Bitmap
	 */
	public void recycle() {
		setImageBitmap(null);
		if (bitmap != null && !bitmap.isRecycled())
			bitmap.recycle();
	}

	/**
	 * 计算两点间的距离
	 */
	private float spacing(MotionEvent event) {
		float x = event.getX(0) - event.getX(1);
		float y = event.getY(0) - event.getY(1);
		return FloatMath.sqrt(x * x + y * y);
	}

	private float[] center;

	/**
	 * 计算两点间的中心点
	 */
	private float[] centerPostion(MotionEvent event) {
		float[] center = new float[2];
		float x = event.getX(0);
		float y = event.getY(0);
		float x1 = event.getX(1);
		float y1 = event.getY(1);
		/* x,y分别的距离 */
		center[0] = Math.abs((x1 - x) / 2);
		center[1] = Math.abs((y1 - y) / 2);
		center[0] = Math.max(x, x1) - center[0];
		center[1] = Math.max(y, y1) - center[1];
		return center;
	}

	/**
	 * 设置ImageView大小等于显示的内容大小
	 */
	public void setRect() {
		float scale = Math.min((float) getWidth() / (float) bmWidth,
				(float) getHeight() / (float) bmHeight);
		int w = (int) ((float) bmWidth * scale) + 1;
		int h = (int) ((float) bmHeight * scale) + 1;
		// int t=(screenH-h)/2;
		// int l=(screenW-w)/2;
		int t = getTop();
		int l = getLeft();
		layout(l, t, l + w, t + h);
	}

	/**
	 * 处理各种移动回弹
	 * 
	 * @param disX
	 *            X的偏移
	 * @param disY
	 *            Y的偏移
	 */
	public void Rebound(int disX, int disY) {
		this.layout(getLeft() + disX, getTop() + disY, getLeft() + disX
				+ getWidth(), getTop() + disY + getHeight());
		if ((AnimSwitch & OPENTRANS) == 0)
			return;
		trans = new TranslateAnimation(-disX, 0, -disY, 0);
		trans.setInterpolator(new AccelerateInterpolator());
		trans.setDuration(300);
		this.startAnimation(trans);
	}

	/**
	 * 处理各种缩放回弹
	 */
	public boolean ReScale() {
		float scaleX = 1f;
		float scaleY = 1f;
		int width = getWidth();
		int height = getHeight();
		int l, t, r, b;
		if (center == null)
			return false;
		if (getWidth() > startWidth * maxScale) {
			while (getWidth() > startWidth * maxScale) {
				l = this.getLeft() + (int) (center[0] * this.getWidth());
				t = this.getTop() + (int) (center[1] * this.getHeight());
				r = this.getRight()
						- (int) ((scale - center[0]) * this.getWidth());
				b = this.getBottom()
						- (int) ((scale - center[1]) * this.getHeight());
				this.setFrame(l, t, r, b);
			}
			scaleX = (float) width / (float) getWidth();
			scaleY = (float) height / (float) getHeight();
		}
		if (getWidth() < startWidth * minScale) {
			while (getWidth() < startWidth * minScale) {
				l = this.getLeft() - (int) (center[0] * this.getWidth());
				t = this.getTop() - (int) (center[1] * this.getHeight());
				r = this.getRight()
						+ (int) ((scale - center[0]) * this.getWidth());
				b = this.getBottom()
						+ (int) ((scale - center[1]) * this.getHeight());
				this.setFrame(l, t, r, b);
			}
			scaleX = (float) width / (float) getWidth();
			scaleY = (float) height / (float) getHeight();
		}

		if (scaleX == 1f && scaleY == 1f)
			return false;
		if ((AnimSwitch & OPENSCALE) == 0) {
			setRect();
			onRebound();
			return true;
		}
		ScaleAnimation scaleanim = new ScaleAnimation(scaleX, 1f, scaleY, 1f,
				ScaleAnimation.RELATIVE_TO_SELF, piovtX,
				ScaleAnimation.RELATIVE_TO_SELF, piovtY);
		scaleanim.setDuration(300);
		scaleanim.setInterpolator(new AccelerateInterpolator());
		scaleanim.setAnimationListener(new AnimationListener() {
			@Override
			public void onAnimationStart(Animation paramAnimation) {
			}

			@Override
			public void onAnimationRepeat(Animation paramAnimation) {
			}

			@Override
			public void onAnimationEnd(Animation paramAnimation) {
				setRect();
				onRebound();
			}

		});
		this.startAnimation(scaleanim);
		return true;
	}

	/**
	 * 处理超范围回弹
	 */
	private void onRebound() {
		/* 判断是否超出范围 并处理 */
		int disX = 0, disY = 0;
		if (getHeight() < screenH) {
			disY = (screenH - getHeight()) / 2 - getTop();
		}
		if (getWidth() < screenW) {
			disX = (screenW - getWidth()) / 2 - getLeft();
		}
		if (getHeight() >= screenH) {
			if (getTop() > 0)
				disY = -getTop();
			if (getBottom() < screenH)
				disY = screenH - getBottom();
		}
		if (getWidth() >= screenW) {
			if (getLeft() > 0)
				disX = -getLeft();
			if (getRight() < screenW)
				disX = screenW - getRight();
		}
		// 开始回弹
		Rebound(disX, disY);
	}

	@Override
	protected void onLayout(boolean changed, int left, int top, int right,
			int bottom) {
		// TODO Auto-generated method stub
		super.onLayout(changed, left, top, right, bottom);
		if (startWidth == 0) {
			startWidth = right - left;
			setRect();
			AnimSwitch = 0;
			onRebound();
			AnimSwitch = OPENSCALE | OPENTRANS;
		}
	}

	/**
	 * 处理触碰..
	 */
	@Override
	public boolean onTouchEvent(MotionEvent event) {
		switch (event.getAction() & MotionEvent.ACTION_MASK) {
		case MotionEvent.ACTION_DOWN:
			mode = DRAG;
			stop_x = (int) event.getRawX();
			stop_y = (int) event.getRawY();
			start_x = (int) event.getX();
			start_y = stop_y - this.getTop();
			if (event.getPointerCount() == 2)
				beforeLenght = spacing(event);
			break;
		case MotionEvent.ACTION_POINTER_DOWN:
			/** 下面三句用于计算缩放中心点位置 **/
			center = centerPostion(event);
			piovtX = center[0] / getWidth();
			piovtY = center[1] / getHeight();

			center[0] = (center[0] / getWidth()) * scale;
			center[1] = (center[1] / getHeight()) * scale;
			if (spacing(event) > 10f) {
				mode = ZOOM;
				beforeLenght = spacing(event);
			}
			break;
		case MotionEvent.ACTION_UP:
			mode = NONE;
			//setRect();
			/* 判断是否超过缩放界限 */
			//if (!ReScale())
			//	onRebound();
			break;
		case MotionEvent.ACTION_POINTER_UP:
			mode = NONE;
			break;
		case MotionEvent.ACTION_MOVE:
			/* 处理拖动 */
			if (mode == DRAG) {
				this.setPosition(stop_x - start_x, stop_y - start_y, stop_x
						+ this.getWidth() - start_x,
						stop_y - start_y + this.getHeight());
				stop_x = (int) event.getRawX();
				stop_y = (int) event.getRawY();
			}
			/* 处理缩放 */
			else if (mode == ZOOM) {
				if (spacing(event) > 10f) {
					afterLenght = spacing(event);
					float gapLenght = afterLenght - beforeLenght;
					if (gapLenght == 0) {
						break;
					} else if (Math.abs(gapLenght) > 5f) {
						if (gapLenght > 0) {
							this.setScale(scale, BIGGER);
						} else {
							this.setScale(scale, SMALLER);
						}
						beforeLenght = afterLenght;
					}
				}
			}
			break;
		}
		return true;
	}

	/**
	 * 实现处理缩放
	 */
	private void setScale(float temp, int flag) {
		int l = 0, t = 0, r = 0, b = 0;
		if (flag == BIGGER) {
			l = this.getLeft() - (int) (center[0] * this.getWidth());
			t = this.getTop() - (int) (center[1] * this.getHeight());
			r = this.getRight() + (int) ((scale - center[0]) * this.getWidth());
			b = this.getBottom()
					+ (int) ((scale - center[1]) * this.getHeight());
		} else if (flag == SMALLER) {
			l = this.getLeft() + (int) (center[0] * this.getWidth());
			t = this.getTop() + (int) (center[1] * this.getHeight());
			r = this.getRight() - (int) ((scale - center[0]) * this.getWidth());
			b = this.getBottom()
					- (int) ((scale - center[1]) * this.getHeight());
		}
		this.setFrame(l, t, r, b);
	}

	/**
	 * 实现处理拖动
	 */
	private void setPosition(int left, int top, int right, int bottom) {
		this.layout(left, top, right, bottom);
	}
}


 类似资料: