自定义可伸缩的imageView
直接上代码
/** * 自定义可伸缩的ImageView */ public class ZoomImageView extends ImageView { /** 画笔类 **/ private Paint mPaint; private Runnable mRefresh = null; /** 缩放手势监听类 **/ private ScaleGestureDetector mScaleDetector; /** 手势识别类 **/ private GestureDetector mGestureDetector; /** 当前被渲染的Bitmap **/ private Bitmap mBitmap; private int mThisWidth = -1, mThisHeight = -1; private Runnable mOnLayoutRunnable = null; private Matrix mBaseMatrix = new Matrix(); private Matrix mDisplayMatrix = new Matrix(); private Matrix mSuppMatrix = new Matrix(); private Matrix mMatrix = new Matrix(); /** 最大的拉伸比例 **/ private float mMaxZoom; private float[] mMatrixValues = new float[9]; private Runnable mFling = null; private double mLastDraw = 0; static final int sPaintDelay = 250; public ZoomImageView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); init(); } public ZoomImageView(Context context, AttributeSet attrs) { super(context, attrs); init(); } public ZoomImageView(Context context) { super(context); init(); } @SuppressLint("NewApi") private void init() { mPaint = new Paint(); // 图像抖动处理 mPaint.setDither(true); // 过滤优化操作 加快显示 mPaint.setFilterBitmap(true); // 去掉锯齿 mPaint.setAntiAlias(true); /** 刷新线程 **/ mRefresh = new Runnable() { @Override public void run() { postInvalidate(); } }; mScaleDetector = new ScaleGestureDetector(getContext(), new ScaleListener()); mGestureDetector = new GestureDetector(getContext(), new MyGestureListener()); // 判断是否是新的API 开启硬件加速 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) { setLayerType(View.LAYER_TYPE_HARDWARE, null); } } public Bitmap getImageBitmap() { return mBitmap; } /** 回收Bitmap **/ public void clear() { if (mBitmap != null && !mBitmap.isRecycled()) { mBitmap.recycle(); mBitmap = null; } } @Override protected void onLayout(boolean changed, int left, int top, int right, int bottom) { super.onLayout(changed, left, top, right, bottom); mThisWidth = right - left; mThisHeight = bottom - top; Runnable r = mOnLayoutRunnable; if (r != null) { mOnLayoutRunnable = null; r.run(); } if (mBitmap != null) { setBaseMatrix(mBitmap, mBaseMatrix); setImageMatrix(getImageViewMatrix()); } } private void setBaseMatrix(Bitmap bitmap, Matrix matrix) { float viewWidth = getWidth(); float viewHeight = getHeight(); matrix.reset(); float widthScale = Math .min(viewWidth / (float) bitmap.getWidth(), 1.0f); float heightScale = Math.min(viewHeight / (float) bitmap.getHeight(), 1.0f); float scale; if (widthScale > heightScale) { scale = heightScale; } else { scale = widthScale; } /** 算取比例 进行平移 **/ matrix.setScale(scale, scale); matrix.postTranslate( (viewWidth - ((float) bitmap.getWidth() * scale)) / 2F, (viewHeight - ((float) bitmap.getHeight() * scale)) / 2F); } public Matrix getImageViewMatrix() { mDisplayMatrix.set(mBaseMatrix); mDisplayMatrix.postConcat(mSuppMatrix); return mDisplayMatrix; } public void setImageMatrix(Matrix m) { /** Matrix是否为空并是否定义 **/ if (m != null && m.isIdentity()) { m = null; } if (m == null && !this.mMatrix.isIdentity() || m != null && !this.mMatrix.equals(m)) { this.mMatrix.set(m); invalidate(); } } static private void translatePoint(Matrix matrix, float[] xy) { matrix.mapPoints(xy); } /** * 设置Bitmap * * @param bitmap */ @SuppressLint("NewApi") public void setImageBitmap(final Bitmap bitmap) { final int viewWidth = getWidth(); // 开启硬件加速 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB && bitmap != null && bitmap.getHeight() > 1800) { setLayerType(View.LAYER_TYPE_SOFTWARE, null); } if (viewWidth <= 0) { mOnLayoutRunnable = new Runnable() { public void run() { setImageBitmap(bitmap); } }; return; } if (bitmap != null) { setBaseMatrix(bitmap, mBaseMatrix); this.mBitmap = bitmap; } else { mBaseMatrix.reset(); this.mBitmap = bitmap; } mSuppMatrix.reset(); setImageMatrix(getImageViewMatrix()); mMaxZoom = maxZoom(); zoomTo(zoomDefault()); } public void zoomTo(float scale) { float width = getWidth(); float height = getHeight(); zoomTo(scale, width / 2F, height / 2F); } protected void zoomTo(float scale, float centerX, float centerY) { if (scale > mMaxZoom) { scale = mMaxZoom; } float oldScale = getScale(); float deltaScale = scale / oldScale; /** 根据某个中心点按照比例缩放 **/ mSuppMatrix.postScale(deltaScale, deltaScale, centerX, centerY); setImageMatrix(getImageViewMatrix()); center(true, true, false); } /** * 计算中心位置 * * @param vertical * @param horizontal * @param animate */ protected void center(boolean vertical, boolean horizontal, boolean animate) { if (mBitmap == null) return; Matrix m = getImageViewMatrix(); float[] topLeft = new float[] { 0, 0 }; float[] botRight = new float[] { mBitmap.getWidth(), mBitmap.getHeight() }; translatePoint(m, topLeft); translatePoint(m, botRight); float height = botRight[1] - topLeft[1]; float width = botRight[0] - topLeft[0]; float deltaX = 0, deltaY = 0; if (vertical) { int viewHeight = getHeight(); if (height < viewHeight) { deltaY = (viewHeight - height) / 2 - topLeft[1]; } else if (topLeft[1] > 0) { deltaY = -topLeft[1]; } else if (botRight[1] < viewHeight) { deltaY = getHeight() - botRight[1]; } } if (horizontal) { int viewWidth = getWidth(); if (width < viewWidth) { deltaX = (viewWidth - width) / 2 - topLeft[0]; } else if (topLeft[0] > 0) { deltaX = -topLeft[0]; } else if (botRight[0] < viewWidth) { deltaX = viewWidth - botRight[0]; } } postTranslate(deltaX, deltaY); if (animate) { Animation a = new TranslateAnimation(-deltaX, 0, -deltaY, 0); a.setStartTime(SystemClock.elapsedRealtime()); a.setDuration(250); setAnimation(a); } setImageMatrix(getImageViewMatrix()); } protected void postTranslate(float dx, float dy) { mSuppMatrix.postTranslate(dx, dy); } public float getScale() { return getScale(mSuppMatrix); } protected float getScale(Matrix matrix) { if (mBitmap != null) return getValue(matrix, Matrix.MSCALE_X); else return 1f; } protected float getValue(Matrix matrix, int whichValue) { matrix.getValues(mMatrixValues); return mMatrixValues[whichValue]; } /** * 计算最大的拉伸比例 * * @return */ protected float maxZoom() { if (mBitmap == null) return 1F; float fw = (float) mBitmap.getWidth() / (float) mThisWidth; float fh = (float) mBitmap.getHeight() / (float) mThisHeight; float max = Math.max(fw, fh) * 16; return max; } /** * 原始显示比例 * * @return */ public float zoomDefault() { if (mBitmap == null) return 1F; float fw = (float) mThisWidth / (float) mBitmap.getWidth(); float fh = (float) mThisHeight / (float) mBitmap.getHeight(); return Math.max(Math.min(fw, fh), 1); } protected void zoomTo(final float scale, final float centerX, final float centerY, final float durationMs) { final float incrementPerMs = (scale - getScale()) / durationMs; final float oldScale = getScale(); final long startTime = System.currentTimeMillis(); post(new Runnable() { public void run() { long now = System.currentTimeMillis(); float currentMs = Math.min(durationMs, (float) (now - startTime)); float target = oldScale + (incrementPerMs * currentMs); zoomTo(target, centerX, centerY); if (currentMs < durationMs) { post(this); } } }); } protected void scrollBy(float distanceX, float distanceY, final float durationMs) { final float dx = distanceX; final float dy = distanceY; final long startTime = System.currentTimeMillis(); mFling = new Runnable() { float old_x = 0; float old_y = 0; public void run() { long now = System.currentTimeMillis(); float currentMs = Math.min(durationMs, now - startTime); float x = easeOut(currentMs, 0, dx, durationMs); float y = easeOut(currentMs, 0, dy, durationMs); postTranslate((x - old_x), (y - old_y)); center(true, true, false); old_x = x; old_y = y; if (currentMs < durationMs) { post(this); } } }; post(mFling); } private float easeOut(float time, float start, float end, float duration) { return end * ((time = time / duration - 1) * time * time + 1) + start; } @SuppressLint("NewApi") @Override protected void onDraw(Canvas canvas) { if (mBitmap != null && !mBitmap.isRecycled()) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB && getLayerType() == View.LAYER_TYPE_HARDWARE) { canvas.drawBitmap(mBitmap, mMatrix, null); } else { if ((System.currentTimeMillis() - mLastDraw) > sPaintDelay) { canvas.drawBitmap(mBitmap, mMatrix, mPaint); mLastDraw = System.currentTimeMillis(); } else { canvas.drawBitmap(mBitmap, mMatrix, null); removeCallbacks(mRefresh); postDelayed(mRefresh, sPaintDelay); } } } } /** * @author Administrator * * 手势缩放监听 */ class ScaleListener extends ScaleGestureDetector.SimpleOnScaleGestureListener { @Override public boolean onScale(ScaleGestureDetector detector) { if (detector != null && detector.isInProgress()) { try { float targetScale = getScale() * detector.getScaleFactor(); targetScale = Math.min(maxZoom(), Math.max(targetScale, 1.0f)); zoomTo(targetScale, detector.getFocusX(), detector.getFocusY()); invalidate(); return true; } catch (IllegalArgumentException e) { e.printStackTrace(); } } return false; } }; /** * @author Administrator * * 手势识别监听 */ class MyGestureListener extends GestureDetector.SimpleOnGestureListener { @Override public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) { if ((e1 != null && e1.getPointerCount() > 1) || (e2 != null && e2.getPointerCount() > 1) || (mScaleDetector != null && mScaleDetector.isInProgress())) { return false; } if (getScale() > zoomDefault()) { removeCallbacks(mFling); postTranslate(-distanceX, -distanceY); center(true, true, false); } return true; } @Override public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) { if ((e1 != null && e1.getPointerCount() > 1) || (e2 != null && e2.getPointerCount() > 1)) { return false; } if (mScaleDetector.isInProgress()) { return false; } try { float diffX = e2.getX() - e1.getX(); float diffY = e2.getY() - e1.getY(); if (Math.abs(velocityX) > 800 || Math.abs(velocityY) > 800) { scrollBy(diffX / 2, diffY / 2, 300); invalidate(); } } catch (NullPointerException e) { e.printStackTrace(); } return super.onFling(e1, e2, velocityX, velocityY); } @Override public boolean onDoubleTap(MotionEvent e) { if (getScale() > zoomDefault()) { zoomTo(zoomDefault()); } else zoomTo(zoomDefault() * 3, e.getX(), e.getY(), 200); return true; } @Override public boolean onSingleTapConfirmed(MotionEvent e) { // 设置点击事件 if (mImageTouchedListener != null) { mImageTouchedListener.onImageTouched(); return false; } return super.onSingleTapConfirmed(e); } } @Override public boolean onTouchEvent(MotionEvent event) { if (mBitmap != null) { mScaleDetector.onTouchEvent(event); if (!mScaleDetector.isInProgress()) { mGestureDetector.onTouchEvent(event); } } return true; }; /** * * @author Administrator * * 点击接口 */ private onImageTouchedListener mImageTouchedListener; public interface onImageTouchedListener { void onImageTouched(); } public void setOnImageTouchedListener(onImageTouchedListener listener) { this.mImageTouchedListener = listener; } }