1. 程式人生 > >surfaceView實現圖片縮放拖動功能

surfaceView實現圖片縮放拖動功能

還是老闆牛,多向他學習請教。之前折騰了好一會兒的問題,被老闆一上午搞定。

問題:採用surface來實現多點觸控縮放,拖動顯示功能。

附上初稿程式碼,明天再好好整理下,

public class MySurfaceView3 extends SurfaceView implements
		SurfaceHolder.Callback, OnTouchListener {

	private static final int NONE = 0;// 原始
	private static final int DRAG = 1;// 拖動
	private static final int ZOOM = 2;// 放大
	private int mStatus = NONE;

	private static final float MAX_ZOOM_SCALE = 4.0f;
	private static final float MIN_ZOOM_SCALE = 1.0f;
	private static final float FLOAT_TYPE = 1.0f;
	private float mCurrentMaxScale = MAX_ZOOM_SCALE;
	private float mCurrentScale = 1.0f;

	private Rect mRectSrc = new Rect(); // used for render image.
	private Rect mRectDes = new Rect(); // used for store size of monitor.

	private int mCenterX, mCenterY;
	int mSurfaceHeight, mSurfaceWidth, mImageHeight, mImageWidth;

	private PointF mStartPoint = new PointF();
	private float mStartDistance = 0f;

	private SurfaceHolder mSurHolder = null;
	private Bitmap mBitmap;

	public MySurfaceView3(Context context, AttributeSet attrs) {
		super(context, attrs);
		mSurHolder = getHolder();
		mSurHolder.addCallback(this);
		this.setOnTouchListener(this);

	}

	private void init() {
		mCurrentMaxScale = Math.max(
				MIN_ZOOM_SCALE,
				4 * Math.min(FLOAT_TYPE * mImageHeight / mSurfaceHeight, 1.0f
						* mImageWidth / mSurfaceWidth));
		mCurrentScale = MIN_ZOOM_SCALE;
		mCenterX = mImageWidth / 2;
		mCenterY = mImageHeight / 2;
		calcRect();

	}

	private void adjustCenter() {
		int w = mRectSrc.right - mRectSrc.left;
		int h = mRectSrc.bottom - mRectSrc.top;

		if (mCenterX - w / 2 < 0) {
			mCenterX = w / 2;
			mRectSrc.left = 0;
			mRectSrc.right = w;
		} else if (mCenterX + w / 2 >= mImageWidth) {
			mCenterX = mImageWidth - w / 2;
			mRectSrc.right = mImageWidth;
			mRectSrc.left = mRectSrc.right - w;

		} else {
			mRectSrc.left = mCenterX - w / 2;
			mRectSrc.right = mRectSrc.left + w;
		}

		if (mCenterY - h / 2 < 0) {
			mCenterY = h / 2;
			mRectSrc.top = 0;
			mRectSrc.bottom = h;
		} else if (mCenterY + h / 2 >= mImageHeight) {
			mCenterY = mImageHeight - h / 2;
			mRectSrc.bottom = mImageHeight;
			mRectSrc.top = mRectSrc.bottom - h;
		} else {
			mRectSrc.top = mCenterY - h / 2;
			mRectSrc.bottom = mRectSrc.top + h;
		}

	}

	private void calcRect() {
		int w, h;
		float imageRatio, surfaceRatio;
		imageRatio = FLOAT_TYPE * mImageWidth / mImageHeight;
		surfaceRatio = FLOAT_TYPE * mSurfaceWidth / mSurfaceHeight;

		if (imageRatio < surfaceRatio) {
			h = mSurfaceHeight;
			w = (int) (h * imageRatio);
		} else {
			w = mSurfaceWidth;
			h = (int) (w / imageRatio);
		}

		if (mCurrentScale > MIN_ZOOM_SCALE) {
			w = Math.min(mSurfaceWidth, (int) (w * mCurrentScale));
			h = Math.min(mSurfaceHeight, (int) (h * mCurrentScale));
		} else {
			mCurrentScale = MIN_ZOOM_SCALE;
		}

		mRectDes.left = (mSurfaceWidth - w) / 2;
		mRectDes.top = (mSurfaceHeight - h) / 2;
		mRectDes.right = mRectDes.left + w;
		mRectDes.bottom = mRectDes.top + h;

		float curImageRatio = FLOAT_TYPE * w / h;
		int h2, w2;
		if (curImageRatio > imageRatio) {
			h2 = (int) (mImageHeight / mCurrentScale);
			w2 = (int) (h2 * curImageRatio);
		} else {

			w2 = (int) (mImageWidth / mCurrentScale);
			h2 = (int) (w2 / curImageRatio);
		}
		mRectSrc.left = mCenterX - w2 / 2;
		mRectSrc.top = mCenterY - h2 / 2;
		mRectSrc.right = mRectSrc.left + w2;
		mRectSrc.bottom = mRectSrc.top + h2;
	}

	public void setMaxZoom(float value) {
		mCurrentMaxScale = value;
	}

	public void setBitmap(Bitmap b) {

		if (b == null) {
			return;
		}
		synchronized (MySurfaceView3.class) {
			mBitmap = b;
			if (mImageHeight != mBitmap.getHeight()
					|| mImageWidth != mBitmap.getWidth()) {
				mImageHeight = mBitmap.getHeight();
				mImageWidth = mBitmap.getWidth();
				init();
			}
			showBitmap();
		}

	}

	private void showBitmap() {
		synchronized (MySurfaceView3.class) {
			Canvas c = getHolder().lockCanvas();
			if (c != null && mBitmap != null) {
				c.drawColor(Color.GRAY);
				c.drawBitmap(mBitmap, mRectSrc, mRectDes, null);
				getHolder().unlockCanvasAndPost(c);
			}
		}
	}

	private void dragAction(MotionEvent event) {

		synchronized (MySurfaceView3.class) {
			PointF currentPoint = new PointF();
			currentPoint.set(event.getX(), event.getY());
			int offsetX = (int) currentPoint.x - (int) mStartPoint.x;
			int offsetY = (int) currentPoint.y - (int) mStartPoint.y;
			mStartPoint = currentPoint;

			mCenterX -= offsetX;
			mCenterY -= offsetY;

			adjustCenter();
			showBitmap();
		}
	}

	private void zoomAcition(MotionEvent event) {

		synchronized (MySurfaceView3.class) {

			float newDist = spacing(event);
			float scale = newDist / mStartDistance;
			mStartDistance = newDist;

			mCurrentScale *= scale;
			mCurrentScale = Math.max(FLOAT_TYPE,
					Math.min(mCurrentScale, mCurrentMaxScale));

			calcRect();
			adjustCenter();
			showBitmap();
		}
	}

	@Override
	public boolean onTouch(View v, MotionEvent event) {

		switch (event.getAction() & MotionEvent.ACTION_MASK) {
		case MotionEvent.ACTION_DOWN:
			mStartPoint.set(event.getX(), event.getY());
			mStatus = DRAG;
			break;

		case MotionEvent.ACTION_POINTER_DOWN:
			float distance = spacing(event);
			if (distance > 10f) {

				mStatus = ZOOM;
				mStartDistance = distance;
			}

			break;

		case MotionEvent.ACTION_MOVE:
			if (mStatus == DRAG) {
				dragAction(event);
			} else {

				if (event.getPointerCount() == 1)
					return true;
				zoomAcition(event);
			}
			break;
		case MotionEvent.ACTION_UP:
		case MotionEvent.ACTION_POINTER_UP:
			mStatus = NONE;
			break;
		default:
			break;
		}

		return true;
	}

	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);
	}

	@Override
	public void surfaceCreated(SurfaceHolder holder) {
		// TODO Auto-generated method stub
	}

	// 初始化
	@Override
	public void surfaceChanged(SurfaceHolder holder, int format, int width,
			int height) {

		synchronized (MySurfaceView3.class) {
			mRectDes.set(0, 0, width, height);
			mSurfaceHeight = height;
			mSurfaceWidth = width;
			init();
			if (mBitmap != null) {
				showBitmap();
			}
		}
	}

	@Override
	public void surfaceDestroyed(SurfaceHolder holder) {

	}

}