zoukankan      html  css  js  c++  java
  • 自定义可伸缩的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;
    	}
    }
    

      

  • 相关阅读:
    网络协议笔记-网络层-划分子网、IP数据报的分组转发
    网络协议笔记-网络层-ARP协议
    网络协议笔记-网络层-路由器的作用、IP地址
    postfix找不到libmysqlclient.so.18
    mysql为datetime类型的字段设置默认值current_timestamp,引发 Invalid default value for 错误
    网络协议笔记-数据链路层
    网络协议笔记-物理层
    [转]numpy中数据合并,stack ,concentrate,vstack,hstack
    【转】python中numpy模块下的np.clip()的用法
    推荐:python科学计算pandas/python画图库matplotlib【转】
  • 原文地址:https://www.cnblogs.com/zyandroid/p/5010120.html
Copyright © 2011-2022 走看看