在好例子网,分享、交流、成长!
您当前所在位置:首页Java 开发实例Android平台开发 → 手势滑动图片放大缩小

手势滑动图片放大缩小

Android平台开发

下载此实例
  • 开发语言:Java
  • 实例大小:0.77M
  • 下载次数:13
  • 浏览次数:200
  • 发布时间:2015-10-20
  • 实例类别:Android平台开发
  • 发 布 人:wellthan
  • 文件格式:.zip
  • 所需积分:5
 相关标签: 图片 放大 缩小 滑动

实例介绍

【实例简介】
【实例截图】

【核心代码】

package com.ymw.zoomimage;

import java.util.Observable;
import java.util.Observer;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;

public class ZoomImageView extends View implements Observer {

	/** Paint object used when drawing bitmap. */
	private final Paint mPaint = new Paint(Paint.FILTER_BITMAP_FLAG);

	/** Rectangle used (and re-used) for cropping source image. */
	private final Rect mRectSrc = new Rect();

	/** Rectangle used (and re-used) for specifying drawing area on canvas. */
	private final Rect mRectDst = new Rect();

	/** Object holding aspect quotient */
	private final AspectQuotient mAspectQuotient = new AspectQuotient();

	/** The bitmap that we're zooming in, and drawing on the screen. */
	private Bitmap mBitmap;

	/** State of the zoom. */
	private ZoomState mState;

	private BasicZoomControl mZoomControl;
	private BasicZoomListener mZoomListener;

	public ZoomImageView(Context context, AttributeSet attrs) {
		super(context, attrs);

		mZoomControl = new BasicZoomControl();

		mZoomListener = new BasicZoomListener();
		mZoomListener.setZoomControl(mZoomControl);

		setZoomState(mZoomControl.getZoomState());

		setOnTouchListener(mZoomListener);

		mZoomControl.setAspectQuotient(getAspectQuotient());
	}

	public void zoomImage(float f, float x, float y) {
		mZoomControl.zoom(f, x, y);
	}

	public void setImage(Bitmap bitmap) {
		mBitmap = bitmap;

		mAspectQuotient.updateAspectQuotient(getWidth(), getHeight(),
				mBitmap.getWidth(), mBitmap.getHeight());
		mAspectQuotient.notifyObservers();

		invalidate();
	}

	private void setZoomState(ZoomState state) {
		if (mState != null) {
			mState.deleteObserver(this);
		}

		mState = state;
		mState.addObserver(this);

		invalidate();
	}

	private AspectQuotient getAspectQuotient() {
		return mAspectQuotient;
	}

	@Override
	protected void onDraw(Canvas canvas) {
		if (mBitmap != null && mState != null) {

			Log.d("ZoomImageView", "OnDraw");

			final float aspectQuotient = mAspectQuotient.get();

			final int viewWidth = getWidth();
			final int viewHeight = getHeight();
			final int bitmapWidth = mBitmap.getWidth();
			final int bitmapHeight = mBitmap.getHeight();

			Log.d("ZoomImageView", "viewWidth = "   viewWidth);
			Log.d("ZoomImageView", "viewHeight = "   viewHeight);
			Log.d("ZoomImageView", "bitmapWidth = "   bitmapWidth);
			Log.d("ZoomImageView", "bitmapHeight = "   bitmapHeight);

			final float panX = mState.getPanX();
			final float panY = mState.getPanY();
			final float zoomX = mState.getZoomX(aspectQuotient) * viewWidth
					/ bitmapWidth;
			final float zoomY = mState.getZoomY(aspectQuotient) * viewHeight
					/ bitmapHeight;

			// Setup source and destination rectangles
			mRectSrc.left = (int) (panX * bitmapWidth - viewWidth / (zoomX * 2));
			mRectSrc.top = (int) (panY * bitmapHeight - viewHeight
					/ (zoomY * 2));
			mRectSrc.right = (int) (mRectSrc.left   viewWidth / zoomX);
			mRectSrc.bottom = (int) (mRectSrc.top   viewHeight / zoomY);
			// mRectDst.left = getLeft();
			mRectDst.left = 0;
			mRectDst.top = 0;
			// mRectDst.right = getRight();
			mRectDst.right = getWidth();
			mRectDst.bottom = getHeight();

			// Adjust source rectangle so that it fits within the source image.
			if (mRectSrc.left < 0) {
				mRectDst.left  = -mRectSrc.left * zoomX;
				mRectSrc.left = 0;
			}
			if (mRectSrc.right > bitmapWidth) {
				mRectDst.right -= (mRectSrc.right - bitmapWidth) * zoomX;
				mRectSrc.right = bitmapWidth;
			}
			if (mRectSrc.top < 0) {
				mRectDst.top  = -mRectSrc.top * zoomY;
				mRectSrc.top = 0;
			}
			if (mRectSrc.bottom > bitmapHeight) {
				mRectDst.bottom -= (mRectSrc.bottom - bitmapHeight) * zoomY;
				mRectSrc.bottom = bitmapHeight;
			}

			mRectDst.left = 0;
			mRectDst.top = 0;
			mRectDst.right = viewWidth;
			mRectDst.bottom = viewHeight;

			Log.d("ZoomImageView", "mRectSrc.top"   mRectSrc.top);
			Log.d("ZoomImageView", "mRectSrc.bottom"   mRectSrc.bottom);
			Log.d("ZoomImageView", "mRectSrc.left"   mRectSrc.left);
			Log.d("ZoomImageView", "mRectSrc.right"   mRectSrc.right);

			Log.d("ZoomImageView", "mRectDst.top"   mRectDst.top);
			Log.d("ZoomImageView", "mRectDst.bottom"   mRectDst.bottom);
			Log.d("ZoomImageView", "mRectDst.left"   mRectDst.left);
			Log.d("ZoomImageView", "mRectDst.right"   mRectDst.right);

			canvas.drawBitmap(mBitmap, mRectSrc, mRectDst, mPaint);
		}
	}

	@Override
	protected void onLayout(boolean changed, int left, int top, int right,
			int bottom) {
		super.onLayout(changed, left, top, right, bottom);

		mAspectQuotient.updateAspectQuotient(right - left, bottom - top,
				mBitmap.getWidth(), mBitmap.getHeight());
		mAspectQuotient.notifyObservers();
	}

	@Override
	public void update(Observable observable, Object data) {
		invalidate();
	}

	private class BasicZoomListener implements View.OnTouchListener {

		/** Zoom control to manipulate */
		private BasicZoomControl mZoomControl;

		private float mFirstX = -1;
		private float mFirstY = -1;
		private float mSecondX = -1;
		private float mSecondY = -1;

		private int mOldCounts = 0;

		/**
		 * Sets the zoom control to manipulate
		 * 
		 * @param control
		 *            Zoom control
		 */
		public void setZoomControl(BasicZoomControl control) {
			mZoomControl = control;
		}

		public boolean onTouch(View v, MotionEvent event) {

			switch (event.getAction()) {
			case MotionEvent.ACTION_DOWN:
				mOldCounts = 1;
				mFirstX = event.getX();
				mFirstY = event.getY();
				break;
			case MotionEvent.ACTION_MOVE: {
				float fFirstX = event.getX();
				float fFirstY = event.getY();

				int nCounts = event.getPointerCount();

				if (1 == nCounts) {
					mOldCounts = 1;
					float dx = (fFirstX - mFirstX) / v.getWidth();
					float dy = (fFirstY - mFirstY) / v.getHeight();
					mZoomControl.pan(-dx, -dy);
				} else if (1 == mOldCounts) {
					mSecondX = event.getX(event.getPointerId(nCounts - 1));
					mSecondY = event.getY(event.getPointerId(nCounts - 1));
					mOldCounts = nCounts;
				} else {
					float fSecondX = event
							.getX(event.getPointerId(nCounts - 1));
					float fSecondY = event
							.getY(event.getPointerId(nCounts - 1));

					double nLengthOld = getLength(mFirstX, mFirstY, mSecondX,
							mSecondY);
					double nLengthNow = getLength(fFirstX, fFirstY, fSecondX,
							fSecondY);

					float d = (float) ((nLengthNow - nLengthOld) / v.getWidth());

					mZoomControl.zoom((float) Math.pow(20, d),
							((fFirstX   fSecondX) / 2 / v.getWidth()),
							((fFirstY   fSecondY) / 2 / v.getHeight()));

					mSecondX = fSecondX;
					mSecondY = fSecondY;
				}
				mFirstX = fFirstX;
				mFirstY = fFirstY;

				break;
			}

			}

			return true;
		}

		private double getLength(float x1, float y1, float x2, float y2) {
			return Math.sqrt(Math.pow(x1 - x2, 2)   Math.pow(y1 - y2, 2));
		}
	}

	private class BasicZoomControl implements Observer {

		/** Minimum zoom level limit */
		private static final float MIN_ZOOM = 1;

		/** Maximum zoom level limit */
		private static final float MAX_ZOOM = 16;

		/** Zoom state under control */
		private final ZoomState mState = new ZoomState();

		/** Object holding aspect quotient of view and content */
		private AspectQuotient mAspectQuotient;

		/**
		 * Set reference object holding aspect quotient
		 * 
		 * @param aspectQuotient
		 *            Object holding aspect quotient
		 */
		public void setAspectQuotient(AspectQuotient aspectQuotient) {
			if (mAspectQuotient != null) {
				mAspectQuotient.deleteObserver(this);
			}

			mAspectQuotient = aspectQuotient;
			mAspectQuotient.addObserver(this);
		}

		/**
		 * Get zoom state being controlled
		 * 
		 * @return The zoom state
		 */
		public ZoomState getZoomState() {
			return mState;
		}

		/**
		 * Zoom
		 * 
		 * @param f
		 *            Factor of zoom to apply
		 * @param x
		 *            X-coordinate of invariant position
		 * @param y
		 *            Y-coordinate of invariant position
		 */
		public void zoom(float f, float x, float y) {

			// Log.d("Zoom", "zoom f = "   f);

			final float aspectQuotient = mAspectQuotient.get();

			final float prevZoomX = mState.getZoomX(aspectQuotient);
			final float prevZoomY = mState.getZoomY(aspectQuotient);

			mState.setZoom(mState.getZoom() * f);
			limitZoom();

			final float newZoomX = mState.getZoomX(aspectQuotient);
			final float newZoomY = mState.getZoomY(aspectQuotient);

			// Pan to keep x and y coordinate invariant
			mState.setPanX(mState.getPanX()   (x - .5f)
					* (1f / prevZoomX - 1f / newZoomX));
			mState.setPanY(mState.getPanY()   (y - .5f)
					* (1f / prevZoomY - 1f / newZoomY));

			limitPan();

			mState.notifyObservers();
		}

		/**
		 * Pan
		 * 
		 * @param dx
		 *            Amount to pan in x-dimension
		 * @param dy
		 *            Amount to pan in y-dimension
		 */
		public void pan(float dx, float dy) {
			final float aspectQuotient = mAspectQuotient.get();

			mState.setPanX(mState.getPanX()   dx
					/ mState.getZoomX(aspectQuotient));
			mState.setPanY(mState.getPanY()   dy
					/ mState.getZoomY(aspectQuotient));

			limitPan();

			mState.notifyObservers();
		}

		/**
		 * Help function to figure out max delta of pan from center position.
		 * 
		 * @param zoom
		 *            Zoom value
		 * @return Max delta of pan
		 */
		private float getMaxPanDelta(float zoom) {
			return Math.max(0f, .5f * ((zoom - 1) / zoom));
		}

		/**
		 * Force zoom to stay within limits
		 */
		private void limitZoom() {
			if (mState.getZoom() < MIN_ZOOM) {
				mState.setZoom(MIN_ZOOM);
			} else if (mState.getZoom() > MAX_ZOOM) {
				mState.setZoom(MAX_ZOOM);
			}
		}

		/**
		 * Force pan to stay within limits
		 */
		private void limitPan() {
			final float aspectQuotient = mAspectQuotient.get();

			final float zoomX = mState.getZoomX(aspectQuotient);
			final float zoomY = mState.getZoomY(aspectQuotient);

			final float panMinX = .5f - getMaxPanDelta(zoomX);
			final float panMaxX = .5f   getMaxPanDelta(zoomX);
			final float panMinY = .5f - getMaxPanDelta(zoomY);
			final float panMaxY = .5f   getMaxPanDelta(zoomY);

			if (mState.getPanX() < panMinX) {
				mState.setPanX(panMinX);
			}
			if (mState.getPanX() > panMaxX) {
				mState.setPanX(panMaxX);
			}
			if (mState.getPanY() < panMinY) {
				mState.setPanY(panMinY);
			}
			if (mState.getPanY() > panMaxY) {
				mState.setPanY(panMaxY);
			}
		}

		// Observable interface implementation

		public void update(Observable observable, Object data) {
			limitZoom();
			limitPan();
		}
	}

	private class AspectQuotient extends Observable {

		/**
		 * Aspect quotient
		 */
		private float mAspectQuotient;

		// Public methods

		/**
		 * Gets aspect quotient
		 * 
		 * @return The aspect quotient
		 */
		public float get() {
			return mAspectQuotient;
		}

		/**
		 * Updates and recalculates aspect quotient based on supplied view and
		 * content dimensions.
		 * 
		 * @param viewWidth
		 *            Width of view
		 * @param viewHeight
		 *            Height of view
		 * @param contentWidth
		 *            Width of content
		 * @param contentHeight
		 *            Height of content
		 */
		public void updateAspectQuotient(float viewWidth, float viewHeight,
				float contentWidth, float contentHeight) {
			final float aspectQuotient = (contentWidth / contentHeight)
					/ (viewWidth / viewHeight);

			if (aspectQuotient != mAspectQuotient) {
				mAspectQuotient = aspectQuotient;
				setChanged();
			}
		}
	}

	private class ZoomState extends Observable {
		/**
		 * Zoom level A value of 1.0 means the content fits the view.
		 */
		private float mZoom;

		/**
		 * Pan position x-coordinate X-coordinate of zoom window center
		 * position, relative to the width of the content.
		 */
		private float mPanX;

		/**
		 * Pan position y-coordinate Y-coordinate of zoom window center
		 * position, relative to the height of the content.
		 */
		private float mPanY;

		// Public methods

		/**
		 * Get current x-pan
		 * 
		 * @return current x-pan
		 */
		public float getPanX() {
			return mPanX;
		}

		/**
		 * Get current y-pan
		 * 
		 * @return Current y-pan
		 */
		public float getPanY() {
			return mPanY;
		}

		/**
		 * Get current zoom value
		 * 
		 * @return Current zoom value
		 */
		public float getZoom() {
			return mZoom;
		}

		/**
		 * Help function for calculating current zoom value in x-dimension
		 * 
		 * @param aspectQuotient
		 *            (Aspect ratio content) / (Aspect ratio view)
		 * @return Current zoom value in x-dimension
		 */
		public float getZoomX(float aspectQuotient) {
			return Math.min(mZoom, mZoom * aspectQuotient);
		}

		/**
		 * Help function for calculating current zoom value in y-dimension
		 * 
		 * @param aspectQuotient
		 *            (Aspect ratio content) / (Aspect ratio view)
		 * @return Current zoom value in y-dimension
		 */
		public float getZoomY(float aspectQuotient) {
			return Math.min(mZoom, mZoom / aspectQuotient);
		}

		/**
		 * Set pan-x
		 * 
		 * @param panX
		 *            Pan-x value to set
		 */
		public void setPanX(float panX) {
			if (panX != mPanX) {
				mPanX = panX;
				setChanged();
			}
		}

		/**
		 * Set pan-y
		 * 
		 * @param panY
		 *            Pan-y value to set
		 */
		public void setPanY(float panY) {
			if (panY != mPanY) {
				mPanY = panY;
				setChanged();
			}
		}

		/**
		 * Set zoom
		 * 
		 * @param zoom
		 *            Zoom value to set
		 */
		public void setZoom(float zoom) {
			if (zoom != mZoom) {
				mZoom = zoom;
				setChanged();
			}
		}
	}
}

实例下载地址

手势滑动图片放大缩小

不能下载?内容有错? 点击这里报错 + 投诉 + 提问

好例子网口号:伸出你的我的手 — 分享

网友评论

发表评论

(您的评论需要经过审核才能显示)

查看所有0条评论>>

小贴士

感谢您为本站写下的评论,您的评论对其它用户来说具有重要的参考价值,所以请认真填写。

  • 类似“顶”、“沙发”之类没有营养的文字,对勤劳贡献的楼主来说是令人沮丧的反馈信息。
  • 相信您也不想看到一排文字/表情墙,所以请不要反馈意义不大的重复字符,也请尽量不要纯表情的回复。
  • 提问之前请再仔细看一遍楼主的说明,或许是您遗漏了。
  • 请勿到处挖坑绊人、招贴广告。既占空间让人厌烦,又没人会搭理,于人于己都无利。

关于好例子网

本站旨在为广大IT学习爱好者提供一个非营利性互相学习交流分享平台。本站所有资源都可以被免费获取学习研究。本站资源来自网友分享,对搜索内容的合法性不具有预见性、识别性、控制性,仅供学习研究,请务必在下载后24小时内给予删除,不得用于其他任何用途,否则后果自负。基于互联网的特殊性,平台无法对用户传输的作品、信息、内容的权属或合法性、安全性、合规性、真实性、科学性、完整权、有效性等进行实质审查;无论平台是否已进行审查,用户均应自行承担因其传输的作品、信息、内容而可能或已经产生的侵权或权属纠纷等法律责任。本站所有资源不代表本站的观点或立场,基于网友分享,根据中国法律《信息网络传播权保护条例》第二十二与二十三条之规定,若资源存在侵权或相关问题请联系本站客服人员,点此联系我们。关于更多版权及免责申明参见 版权及免责申明

;
报警