比较完整的图片缩放(Android)
来源:互联网 发布:python flask上传图片 编辑:程序博客网 时间:2024/04/29 03:13
跟大家分享一个我写的图片缩放的例子,主要功能是图片双击放大缩小,两指滑动放大缩小,有最大最小缩放比例,压缩有回弹,应该是比较全面了。(在我一哥们写的基础上改的,黑嘿嘿)
public class MyZoomImageView extends ImageView { /** * 原始的Matrix */ private Matrix srcMatrix = new Matrix(); /** * 图片处理的矩阵 */ private Matrix mMatrix = new Matrix(); /** * 图片矩阵的原始数据 */ private float[] mValues = new float[9]; /** * 缩放的最小值 */ private float ZOOM_MIN = 0; /** * 缩放的最大值 */ private float ZOOM_MAX = 0; /** * 缩放默认值 */ private float ZOOM_DEFAULT = 0; /** * 双击之后的缩放值 */ private float ZOOM_DOUBLECLICK = 0; /** * 中心坐标 */ private PointF mid = new PointF(); /** * 手势 */ private GestureDetector mGestrueDetector = null; /** * 图片原宽度 */ private int mImageWidth = 0; /** * 图片原高度 */ private int mImageHeight = 0; /** 用于记录开始时候的坐标位置 */ private PointF startPoint = new PointF(); /** 平移模式 */ private static final int MODE_DRAG = 1; /** 放大缩小照片模式 */ private static final int MODE_ZOOM = 2; /** 不支持Matrix */ private static final int MODE_UNABLE = 3; private int mMode = 0; /** 缩放开始时的手指间距 */ private float mStartDis; public MyZoomImageView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); // TODO Auto-generated constructor stub init(context); } public MyZoomImageView(Context context, AttributeSet attrs) { super(context, attrs); // TODO Auto-generated constructor stub init(context); } public MyZoomImageView(Context context) { super(context); // TODO Auto-generated constructor stub init(context); } private void init(Context context) { System.out.println("init");// viewTreeObserver = getViewTreeObserver();// viewTreeObserver// .addOnGlobalLayoutListener(new MyGrobalLayoutListener()); setScaleType(ScaleType.MATRIX); mGestrueDetector = new GestureDetector(context, new MyGestureListener()); } @Override public void setImageBitmap(Bitmap bm) { // TODO Auto-generated method stub super.setImageBitmap(bm); // 有时会调用setImageBitmap(null) if (bm == null) return; mImageWidth = bm.getWidth(); mImageHeight = bm.getHeight(); fitScreen(); // 保存当前的图片尺寸信息 mMatrix.set(getImageMatrix()); mMatrix.getValues(mValues); //保存原始矩阵 srcMatrix.set(mMatrix); ZOOM_MIN = mValues[Matrix.MSCALE_X]*2/3; ZOOM_DEFAULT = mValues[Matrix.MSCALE_X]; ZOOM_DOUBLECLICK = mValues[Matrix.MSCALE_X] * 2; ZOOM_MAX = mValues[Matrix.MSCALE_X] * 3; } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { // TODO Auto-generated method stub super.onMeasure(widthMeasureSpec, heightMeasureSpec); } private void fitScreen() { System.out.println("fitScreen--->"+getWidth()+" "+mImageWidth); float scaleX = (float) getWidth() / (float) mImageWidth; mMatrix.set(getImageMatrix()); mMatrix.postScale(scaleX, scaleX); // 图片与下边界 的距离 float marginY = getHeight() - scaleX * mImageHeight; if (marginY > 0) { // 说明纵向铺不满 mMatrix.postTranslate(0, marginY / 2f); } // Matrix是从(0,0)左上角开始做的变换 setImageMatrix(mMatrix); } @Override public boolean onTouchEvent(MotionEvent event) { /** 处理单点、多点触摸 **/ switch (event.getAction() & MotionEvent.ACTION_MASK) { // 按下事件 case MotionEvent.ACTION_DOWN: // 设置拖动模式 mMode = MODE_DRAG; startPoint.set(event.getX(), event.getY()); mid.set(getWidth() / 2, getHeight() / 2); break; // 多点触摸 case MotionEvent.ACTION_POINTER_DOWN:// killThread = true; if (mMode == MODE_UNABLE) return true; mMode = MODE_ZOOM; mStartDis = getDistance(event); midPoint(mid, event); break; case MotionEvent.ACTION_MOVE: if (mMode == MODE_DRAG) { float dx = event.getX() - startPoint.x; // 得到x轴的移动距离 float dy = event.getY() - startPoint.y; // 得到y轴的移动距离 // 避免和双击冲突,大于10f才算是拖动 if (Math.sqrt(dx * dx + dy * dy) > 10f) { startPoint.set(event.getX(), event.getY()); // 在当前基础上移动 mMatrix.set(getImageMatrix()); float[] values = new float[9]; mMatrix.getValues(values); dx = checkDxBound(values, dx); dy = checkDyBound(values, dy); mMatrix.postTranslate(dx, dy); setImageMatrix(mMatrix); } } else if (mMode == MODE_ZOOM) { float endDis = getDistance(event); if (endDis > 10f) { // 两个手指并拢在一起的时候像素大于10 float scale = endDis / mStartDis;// 得到缩放倍数 setZoom(scale); mStartDis = endDis;// 重置距离 } } break; case MotionEvent.ACTION_CANCEL: // break; case MotionEvent.ACTION_UP: mMode = 0; break; // 多点松开 case MotionEvent.ACTION_POINTER_UP: mMode = 0; resetToDefault(); default: break; } return mGestrueDetector.onTouchEvent(event); } private void resetToDefault(){ float[] values = new float[9]; getImageMatrix().getValues(values); // 获取当前X轴缩放级别 float scale = values[Matrix.MSCALE_X]; System.out.println(scale+" "+ZOOM_DEFAULT); if(scale<ZOOM_DEFAULT){ setImageMatrix(srcMatrix); } }// private boolean killThread = false;// class ResetThread extends Thread{// private float scale = 0;// public ResetThread(float scale){// this.scale = scale;// }// @Override// public void run() {// while(!this.isInterrupted()&&!killThread){// if(scale<ZOOM_DEFAULT){// scale = scale+0.1f;// Message msg = Message.obtain();// msg.obj = scale;// myHandler.sendMessage(msg);// }else if(scale >ZOOM_DEFAULT){// Message msg = Message.obtain();// msg.obj = ZOOM_DEFAULT;// myHandler.sendMessage(msg);// break;// }// try {// Thread.sleep(10);// } catch (InterruptedException e) {// // TODO Auto-generated catch block// e.printStackTrace();// }// }// }// } /** * 计算两个手指间的距离 * * @param event * @return */ private float getDistance(MotionEvent event) { float dx = event.getX(1) - event.getX(0); float dy = event.getY(1) - event.getY(0); /** 使用勾股定理返回两点之间的距离 */ return (float) Math.sqrt(dx * dx + dy * dy); } // 取手势中心点 private void midPoint(PointF point, MotionEvent event) { float x = event.getX(0) + event.getX(1); float y = event.getY(0) + event.getY(1); point.set(x / 2, y / 2); } /** * 和当前矩阵对比,检验dx,使图像移动后不会超出ImageView边界 * * @param values * @param dx * @return */ private float checkDxBound(float[] values, float dx) { float width = getWidth(); if (mImageWidth * values[Matrix.MSCALE_X] < width) { // 当控件能容纳整张图片时,让图片保持正中 dx = (getWidth() - mImageWidth * values[Matrix.MSCALE_X]) / 2 - values[Matrix.MTRANS_X]; } else if (values[Matrix.MTRANS_X] + dx > 0) dx = -values[Matrix.MTRANS_X]; else if (values[Matrix.MTRANS_X] + dx < -(mImageWidth * values[Matrix.MSCALE_X] - width)) dx = -(mImageWidth * values[Matrix.MSCALE_X] - width) - values[Matrix.MTRANS_X]; return dx; } /** * 和当前矩阵对比,检验dy,使图像移动后不会超出ImageView边界 * * @param values * @param dy * @return */ private float checkDyBound(float[] values, float dy) { // 获取ImageView控件高度 float height = getHeight(); // mImageHeight=sitImageBitmap方法中获取的图片高度 // values[Matrix.MSCALE_Y]当前Y轴缩放级别计算出当前Y轴的显示高度 if (mImageHeight * values[Matrix.MSCALE_Y] < height) { // 图片的纵向全部显示了 dy = (getHeight() - mImageHeight * values[Matrix.MSCALE_Y]) / 2 - values[Matrix.MTRANS_Y]; } else if (values[Matrix.MTRANS_Y] + dy > 0) { dy = -values[Matrix.MTRANS_Y]; } else if (values[Matrix.MTRANS_Y] + dy < -(mImageHeight * values[Matrix.MSCALE_Y] - height)) { dy = -(mImageHeight * values[Matrix.MSCALE_Y] - height) - values[Matrix.MTRANS_Y]; } return dy; } /** * 双击放缩图片 */ public void onDoubleClick(MotionEvent e) { float[] values = new float[9]; getImageMatrix().getValues(values); // 获取当前X轴缩放级别 float scale = values[Matrix.MSCALE_X]; float tmp; if (scale > ZOOM_DEFAULT) { tmp = ZOOM_DEFAULT / scale; } else { tmp = ZOOM_DOUBLECLICK / scale; } // 将缩放中心设置为双击中心 mid.set(e.getX(), e.getY()); setZoom(tmp); } // scale是相对于当前(不是最初)的大小来进行变化的倍率 private void setZoom(float scale) { // TODO Auto-generated method stub float[] values = new float[9]; // 不要getImageMatrix().getValues(values) mMatrix.set(getImageMatrix()); mMatrix.getValues(values); // 限制放大的最大倍数 if (scale * values[Matrix.MSCALE_X] > ZOOM_MAX) { scale = ZOOM_MAX / values[Matrix.MSCALE_X]; } // 限制缩小的最小倍数 if (scale * values[Matrix.MSCALE_X] < ZOOM_MIN) { scale = ZOOM_MIN / values[Matrix.MSCALE_X]; } if (scale == 1) { return; } mMatrix.postScale(scale, scale, mid.x, mid.y); mMatrix.getValues(values); float dx = checkDxBound(values, 0); float dy = checkDyBound(values, 0); mMatrix.postTranslate(dx, dy); setImageMatrix(mMatrix); } class MyGestureListener extends SimpleOnGestureListener { @Override public boolean onDown(MotionEvent e) { // 捕获Down事件 return true; } @Override public boolean onDoubleTap(MotionEvent e) { // 触发双击事件 onDoubleClick(e); return true; } @Override public boolean onSingleTapUp(MotionEvent e) { // TODO Auto-generated method stub return super.onSingleTapUp(e); } @Override public void onLongPress(MotionEvent e) { // TODO Auto-generated method stub super.onLongPress(e); } @Override public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) { return super.onScroll(e1, e2, distanceX, distanceY); } @Override public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) { // TODO Auto-generated method stub return super.onFling(e1, e2, velocityX, velocityY); } @Override public void onShowPress(MotionEvent e) { // TODO Auto-generated method stub super.onShowPress(e); } @Override public boolean onDoubleTapEvent(MotionEvent e) { // TODO Auto-generated method stub return super.onDoubleTapEvent(e); } @Override public boolean onSingleTapConfirmed(MotionEvent e) { // TODO Auto-generated method stub return super.onSingleTapConfirmed(e); } }}
注释应该比较详细了,我也就不仔细分解了,分解什么的都是浮云,还是得看代码。注意一个问题就是这个ImageView必须要加载完成之后才能setImageBitmap,不然会出现不显示或者显示效果不好的结果的,要注意哦。(也就是说这个图片要异步加载的哦)
0 0
- 比较完整的图片缩放(Android)
- android图片的缩放
- android图片的缩放
- android图片的缩放 .
- android图片的缩放
- Android图片的缩放
- Android图片缩放总结及比较
- Android图片缩放总结及比较
- Android图片缩放总结及比较
- Android图片缩放总结及比较
- Android图片缩放总结及比较
- Android图片缩放总结及比较
- Android ImageView手势缩放完整的实现
- Android图片的缩放处理
- Android中图片的缩放
- Android图片的缩放问题
- android图片的定时缩放
- Android的图片缩放、拖动
- 云计算大数据时代从空调到电视的演变你想到了什么?
- Protocol Buffer技术详解(数据编码)
- Java中的ReentrantLock和synchronized两种锁定机制的对比
- POJ2688状态压缩(可以+DFS剪枝)
- JMX 入门例子
- 比较完整的图片缩放(Android)
- Unity3D架构系列之- FSM有限状态机设计(四)
- javascript的数据类型
- kafka A
- 网页静态化
- POJ2771最大独立集元素个数
- js数组的操作
- 快速排序
- 2013年蓝桥杯之猜年龄