可缩放的ImageView
来源:互联网 发布:小河淌水 知乎 编辑:程序博客网 时间:2024/04/30 07:43
本博客为 http://www.imooc.com/learn/239 的笔记
/** * * 首先在 onGlobalLayout() 中将图片缩放居中 * 然后在缩放手势中 对图片进行缩放,并进行边界的检测 * 然后 在touchEnvent中对图片进行平移 * 然后 在手势中 对双击事件进行处理,实现对图片的缩放 * 最后,对父控件的事件拦截进行条件的判断并且处理 * */public class ZoomImageView extends ImageView implements OnGlobalLayoutListener, OnTouchListener, OnScaleGestureListener { private Context ctx; // 对图片操作的类 private Matrix scaleMatrix; //测量标志位,避免多次的测量造成的误差 private boolean isOnce; //最初的缩放比例 private float initScale=0; //双击之后的缩放比例 private float MidScale=0; //最大的缩放比例 private float MaxScale=0; //----------------------------------------------------------------- //缩放手势 private ScaleGestureDetector scaleGestureDetector; //----------------------------------------------------------------- // 图片的平移 //上一次的多指触控的数目 private int mLastPointCount; ///上一次中心点的坐标 private float mLastCenterX; private float mLastCenterY; //移动的临界点 private float mTouchSlop; //------------------------------------------------------------------ //操作手势 private GestureDetector detector; //是否在缩放 private boolean isAuto; public ZoomImageView(Context context, AttributeSet attrs) { this(context, attrs, 0); this.ctx = context; scaleMatrix = new Matrix(); mTouchSlop=ViewConfiguration.get(context).getTouchSlop(); scaleGestureDetector=new ScaleGestureDetector(ctx, this); //处理双击事件 detector=new GestureDetector(ctx, new GestureDetector.SimpleOnGestureListener(){ @Override public boolean onDoubleTap(MotionEvent e) { if(!isAuto){ //获取当前的缩放值 float scale=getScale(); float x=e.getX(); float y=e.getY(); if(scale <MidScale){ postDelayed(new AutoScaleRunnable(MidScale, x, y), 16); isAuto=true; }else{ postDelayed(new AutoScaleRunnable(initScale, x, y), 16); isAuto=true; } } return super.onDoubleTap(e); } }); setOnTouchListener(this); super.setScaleType(ScaleType.MATRIX); } public ZoomImageView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); } public ZoomImageView(Context context) { this(context, null); } /** * 实现缓慢的缩放 */ class AutoScaleRunnable implements Runnable { private float targetScale; private float centerX; private float centerY; // 临时的缩放比例 private float tempScale; /** * * @param targetScale 目标的缩放比例 * @param centerX 缩放的中心 * @param centerY 缩放的中心 */ public AutoScaleRunnable(float targetScale, float centerX, float centerY) { this.targetScale = targetScale; this.centerX = centerX; this.centerY = centerY; float curScale = getScale(); if (curScale < targetScale) { // /放大 tempScale = 1.07f; } else { // 缩小 tempScale = 0.93f; } } @Override public void run() { scaleMatrix.postScale(tempScale, tempScale, centerX, centerY); checkBorderAndCenter(); setImageMatrix(scaleMatrix); float curScale = getScale(); if ((tempScale < 1.0f && curScale > targetScale) || (tempScale > 1.0f && curScale < targetScale)) { // 继续执行线程 postDelayed(this, 16); } else { float scale = targetScale / curScale; scaleMatrix.postScale(scale, scale, centerX, centerY); checkBorderAndCenter(); setImageMatrix(scaleMatrix); isAuto = false; } } }; @Override protected void onAttachedToWindow() { super.onAttachedToWindow(); getViewTreeObserver().addOnGlobalLayoutListener(this); } @SuppressLint("NewApi") @Override protected void onDetachedFromWindow() { super.onDetachedFromWindow(); getViewTreeObserver().removeOnGlobalLayoutListener(this); } @Override public void onGlobalLayout() { if (!isOnce) { Drawable d=getDrawable(); if(d==null){ return ; } //获取控件的宽高 int width=getWidth(); int height=getHeight(); //获取图片的宽高 int dw=d.getIntrinsicWidth(); int dh=d.getIntrinsicHeight(); //图片缩放比例 float scale=0; if(dw >width && dh >height){ scale=Math.min((width*1.0f/dw),(height*1.0f/dh)); } if(dw<width && dh <height){ scale=Math.min((width*1.0f/dw), (height*1.0f/dh)); } if(dw >width && dh <height){ scale=width*1.0f/dw; } if(dw <width && dh >height){ scale=height*1.0f/dh; } initScale=scale; MidScale=initScale*2; MaxScale=initScale*4; float offX=getWidth()/2-dw/2; float offY=getHeight()/2-dh/2; //先平移,然后缩放 scaleMatrix.postTranslate(offX, offY); //缩放的中心为控件的中心 scaleMatrix.postScale(scale, scale, getWidth()/2, getHeight()/2); setImageMatrix(scaleMatrix); isOnce = true; } } /** * 获取当前图片的缩放比例 * @return */ public float getScale(){ float[] values=new float[9]; scaleMatrix.getValues(values); return values[Matrix.MSCALE_X]; } @Override public boolean onTouch(View arg0, MotionEvent arg1) { if(detector.onTouchEvent(arg1)){ return true; } scaleGestureDetector.onTouchEvent(arg1); int pCount=arg1.getPointerCount(); //中心点的坐标 float centerX=0; float centerY=0; for(int i=0;i<pCount;i++){ centerX+=arg1.getX(i); centerY+=arg1.getY(); } centerX/=pCount; centerY/=pCount; if(mLastPointCount!=pCount){ mLastCenterX=centerX; mLastCenterY=centerY; } mLastPointCount=pCount; float dx=centerX-mLastCenterX; float dy=centerY-mLastCenterY; switch(arg1.getAction()){ case MotionEvent.ACTION_DOWN: RectF rectf1=getMatrixRectF(); if(rectf1.width() >getWidth() || rectf1.height() >getHeight()){ //请求父控件不要拦截事件 this.getParent().requestDisallowInterceptTouchEvent(true); } break; case MotionEvent.ACTION_MOVE: RectF rectf2=getMatrixRectF(); if(rectf2.width() >getWidth() || rectf2.height() >getHeight()){ this.getParent().requestDisallowInterceptTouchEvent(true); } if(Math.sqrt((dx*dx+dy*dy))>mTouchSlop){ RectF rectf=getMatrixRectF(); if(rectf.width() <getWidth()){ dx=0; } if(rectf.height()<getHeight()){ dy=0; } //平移 scaleMatrix.postTranslate(dx, dy); checkBorderAndCenter(); setImageMatrix(scaleMatrix); } break; case MotionEvent.ACTION_UP: mLastPointCount=0; break; } return true; } @Override public boolean onScale(ScaleGestureDetector arg0) { //缩放的因子 float factor=arg0.getScaleFactor(); //获取当前图片的缩放比例 float scale=getScale(); if((factor<1.0f && scale >initScale) ||(factor >1.0f && scale <MaxScale)){ if(scale *factor >MaxScale){ factor=MaxScale*1.0f/scale; } if(scale *factor <initScale){ factor=initScale*1.0f/scale; } scaleMatrix.postScale(factor, factor, arg0.getFocusX(), arg0.getFocusY()); checkBorderAndCenter(); setImageMatrix(scaleMatrix); } return false; } /** * 获取图片的宽高与四点坐标的值 * @return */ public RectF getMatrixRectF(){ RectF rectf=new RectF(); Drawable d=getDrawable(); Matrix matrix=scaleMatrix; if(d!=null){ rectf.set(0,0,d.getIntrinsicWidth(),d.getIntrinsicHeight()); matrix.mapRect(rectf); return rectf; } return rectf; } /** * 在缩放的过程中进行边界与中心的检测 */ private void checkBorderAndCenter() { int height=getHeight(); int width=getWidth(); float dx=0; float dy=0; RectF rectf=getMatrixRectF(); if(rectf.width() >=getWidth()){ if(rectf.left>0){ dx=-rectf.left; } if(rectf.right<width){ dx=width-rectf.right; } } if(rectf.height() >=getHeight()){ if(rectf.top >0){ dy=-rectf.top; } if(rectf.bottom <height){ dy=height-rectf.bottom; } } // 当图片的宽小于控件的宽度 if (rectf.width() < getWidth()) { dx = getWidth() / 2 - rectf.right + rectf.width() / 2; } // 当图片的高度小于控件的高度 if (rectf.height() < getHeight()) { dy = getHeight() / 2 - rectf.bottom + rectf.height() / 2; } scaleMatrix.postTranslate(dx, dy); } @Override public boolean onScaleBegin(ScaleGestureDetector arg0) { return true; } @Override public void onScaleEnd(ScaleGestureDetector arg0) { }}
0 0
- 可缩放的ImageView
- Android 可平移,缩放,旋转的ImageView
- ViewPager+可缩放ImageView的使用
- 自定义可缩放图片的ImageView
- Android viewpager + 可缩放的imageview
- Android 可缩放ImageView
- android imageview自定义可缩放
- 可平移缩放旋转的ImageView的实现
- Android:手把手教你打造可缩放移动的ImageView
- Android自定义可缩放的ImageView,长按可弹出菜单
- ImageView的缩放模式
- ImageView的缩放模式
- ImageView的缩放
- ImageView的缩放模式
- ImageView 的缩放 scaleType
- ImageView的缩放:scaleType
- 谈谈ImageView的缩放
- <Android>打造自己的可双击放大、多指缩放、放大等功能的ImageView
- MODBUS协议和RS232,RS485,SPI,IIC,CAN总线有什么区别
- C++ 星图编程
- 十三种基于直方图的图像全局二值化算法原理、实现、代码及效果。
- 通过工厂模式随时切换百度地图和高德地图
- 面试问题
- 可缩放的ImageView
- 最基本的商业模式
- java线程池
- MIT算法导论-第10讲-2-3树、红黑树
- Android Volley完全解析
- 头像变圆圈并转动代码
- ADO.NET之command查询数据
- java序列化反序列化uid
- Android创建Virtual Devices时出错