今天介绍一下Android中怎么实现ImageView的缩放和移动,自定义TouchImageView。
1 public class TouchImageView extends ImageView { 2 3 Matrix matrix; 4 5 // We can be in one of these 3 states 6 static final int NONE = 0; 7 static final int DRAG = 1; 8 static final int ZOOM = 2; 9 int mode = NONE; 10 11 // Remember some things for zooming 12 PointF last = new PointF(); 13 PointF start = new PointF(); 14 float minScale = 1f; 15 float maxScale = 3f; 16 float[] m; 17 18 19 int viewWidth, viewHeight; 20 static final int CLICK = 3; 21 float saveScale = 1f; 22 protected float origWidth, origHeight; 23 int oldMeasuredWidth, oldMeasuredHeight; 24 25 26 ScaleGestureDetector mScaleDetector; 27 28 Context context; 29 30 public TouchImageView(Context context) { 31 super(context); 32 sharedConstructing(context); 33 } 34 35 public TouchImageView(Context context, AttributeSet attrs) { 36 super(context, attrs); 37 sharedConstructing(context); 38 } 39 40 private void sharedConstructing(Context context) { 41 super.setClickable(true); 42 this.context = context; 43 mScaleDetector = new ScaleGestureDetector(context, new ScaleListener()); 44 matrix = new Matrix(); 45 m = new float[9]; 46 setImageMatrix(matrix); 47 setScaleType(ScaleType.MATRIX); 48 49 setOnTouchListener(new OnTouchListener() { 50 51 @Override 52 public boolean onTouch(View v, MotionEvent event) { 53 mScaleDetector.onTouchEvent(event); 54 PointF curr = new PointF(event.getX(), event.getY()); 55 56 switch (event.getAction()) { 57 case MotionEvent.ACTION_DOWN: 58 last.set(curr); 59 start.set(last); 60 mode = DRAG; 61 break; 62 63 case MotionEvent.ACTION_MOVE: 64 if (mode == DRAG) { 65 float deltaX = curr.x - last.x; 66 float deltaY = curr.y - last.y; 67 float fixTransX = getFixDragTrans(deltaX, viewWidth, origWidth * saveScale); 68 float fixTransY = getFixDragTrans(deltaY, viewHeight, origHeight * saveScale); 69 matrix.postTranslate(fixTransX, fixTransY); 70 fixTrans(); 71 last.set(curr.x, curr.y); 72 } 73 break; 74 75 case MotionEvent.ACTION_UP: 76 mode = NONE; 77 int xDiff = (int) Math.abs(curr.x - start.x); 78 int yDiff = (int) Math.abs(curr.y - start.y); 79 if (xDiff < CLICK && yDiff < CLICK) 80 performClick(); 81 break; 82 83 case MotionEvent.ACTION_POINTER_UP: 84 mode = NONE; 85 break; 86 } 87 88 setImageMatrix(matrix); 89 invalidate(); 90 return true; // indicate event was handled 91 } 92 93 }); 94 } 95 96 public void setMaxZoom(float x) { 97 maxScale = x; 98 } 99 100 private class ScaleListener extends ScaleGestureDetector.SimpleOnScaleGestureListener { 101 @Override 102 public boolean onScaleBegin(ScaleGestureDetector detector) { 103 mode = ZOOM; 104 return true; 105 } 106 107 @Override 108 public boolean onScale(ScaleGestureDetector detector) { 109 float mScaleFactor = detector.getScaleFactor(); 110 float origScale = saveScale; 111 saveScale *= mScaleFactor; 112 if (saveScale > maxScale) { 113 saveScale = maxScale; 114 mScaleFactor = maxScale / origScale; 115 } else if (saveScale < minScale) { 116 saveScale = minScale; 117 mScaleFactor = minScale / origScale; 118 } 119 120 if (origWidth * saveScale <= viewWidth || origHeight * saveScale <= viewHeight) 121 matrix.postScale(mScaleFactor, mScaleFactor, viewWidth / 2, viewHeight / 2); 122 else 123 matrix.postScale(mScaleFactor, mScaleFactor, detector.getFocusX(), detector.getFocusY()); 124 125 fixTrans(); 126 return true; 127 } 128 } 129 130 void fixTrans() { 131 matrix.getValues(m); 132 float transX = m[Matrix.MTRANS_X]; 133 float transY = m[Matrix.MTRANS_Y]; 134 135 float fixTransX = getFixTrans(transX, viewWidth, origWidth * saveScale); 136 float fixTransY = getFixTrans(transY, viewHeight, origHeight * saveScale); 137 138 if (fixTransX != 0 || fixTransY != 0) 139 matrix.postTranslate(fixTransX, fixTransY); 140 } 141 142 float getFixTrans(float trans, float viewSize, float contentSize) { 143 float minTrans, maxTrans; 144 145 if (contentSize <= viewSize) { 146 minTrans = 0; 147 maxTrans = viewSize - contentSize; 148 } else { 149 minTrans = viewSize - contentSize; 150 maxTrans = 0; 151 } 152 153 if (trans < minTrans) 154 return -trans + minTrans; 155 if (trans > maxTrans) 156 return -trans + maxTrans; 157 return 0; 158 } 159 160 float getFixDragTrans(float delta, float viewSize, float contentSize) { 161 if (contentSize <= viewSize) { 162 return 0; 163 } 164 return delta; 165 } 166 167 @Override 168 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 169 super.onMeasure(widthMeasureSpec, heightMeasureSpec); 170 viewWidth = MeasureSpec.getSize(widthMeasureSpec); 171 viewHeight = MeasureSpec.getSize(heightMeasureSpec); 172 173 // 174 // Rescales image on rotation 175 // 176 if (oldMeasuredHeight == viewWidth && oldMeasuredHeight == viewHeight 177 || viewWidth == 0 || viewHeight == 0) 178 return; 179 oldMeasuredHeight = viewHeight; 180 oldMeasuredWidth = viewWidth; 181 182 if (saveScale == 1) { 183 //Fit to screen. 184 float scale; 185 186 Drawable drawable = getDrawable(); 187 if (drawable == null || drawable.getIntrinsicWidth() == 0 || drawable.getIntrinsicHeight() == 0) 188 return; 189 int bmWidth = drawable.getIntrinsicWidth(); 190 int bmHeight = drawable.getIntrinsicHeight(); 191 192 Log.d("bmSize", "bmWidth: " + bmWidth + " bmHeight : " + bmHeight); 193 194 float scaleX = (float) viewWidth / (float) bmWidth; 195 float scaleY = (float) viewHeight / (float) bmHeight; 196 scale = Math.min(scaleX, scaleY); 197 matrix.setScale(scale, scale); 198 199 // Center the image 200 float redundantYSpace = (float) viewHeight - (scale * (float) bmHeight); 201 float redundantXSpace = (float) viewWidth - (scale * (float) bmWidth); 202 redundantYSpace /= (float) 2; 203 redundantXSpace /= (float) 2; 204 205 matrix.postTranslate(redundantXSpace, redundantYSpace); 206 207 origWidth = viewWidth - 2 * redundantXSpace; 208 origHeight = viewHeight - 2 * redundantYSpace; 209 setImageMatrix(matrix); 210 } 211 fixTrans(); 212 } 213 }