Android 手势滑动,多点触摸放大缩小图片
效果展示:
基本思路:
<1>首先写一个图片控制类ImageControl,实现对图片控制的的基本操作,我们的图片控制类ImageControl是继承自ImageView自定义的视图;
<2>再写一个测试用的布局,这里就要用到自定义的ImageView;
<3>编写测试类ImageViewActivity,写onTouchEvent()方法;
图片控制类ImageControl:
1 package com.basecontrol.view; 2 3 import android.content.Context; 4 import android.graphics.Bitmap; 5 import android.graphics.Matrix; 6 import android.util.AttributeSet; 7 import android.util.FloatMath; 8 import android.view.MotionEvent; 9 import android.widget.ImageView; 10 11 public class ImageControl extends ImageView { 12 13 public ImageControl(Context context) { 14 super(context); 15 } 16 public ImageControl(Context context, AttributeSet attrs) { 17 super(context, attrs); 18 } 19 public ImageControl(Context context, AttributeSet attrs, int defStyle) { 20 super(context, attrs, defStyle); 21 } 22 23 Matrix imgMatrix=null;//定义图片的变换矩阵 24 25 static final int DOUBLE_CLICK_TIME_SPACE=300;//双击时间间隔 26 static final int DOUBLE_POINT_DISTANCE =10;// 两点放大两点间最小间距 27 static final int NONE = 0; 28 private int mode=NONE;//当前模式 29 static final int DRAG=1; 30 static final int ZOOM = 2; // 放大缩小操作 31 32 float bigScale=3f;//默认放大倍数 33 Boolean isBig=false;//是否放大 34 long lastClickTime =0;//单击时间 35 float startDistance;//两点触摸两点距离 36 float endDistance;//多点触摸两点距离 37 38 float topHeight;//状态栏高度和标题栏高度 39 Bitmap primaryBitmap=null; 40 41 float contentW;//屏幕内容区宽度 42 float contentH;//屏幕内容区高度 43 44 float primaryW;//原图宽度 45 float primaryH;//原图高度 46 47 float scale; // 适合屏幕缩放倍数 48 Boolean isMoveX = true; // 是否允许在X轴拖动 49 Boolean isMoveY = true; // 是否允许在Y轴拖动 50 float startX; 51 float startY; 52 float endX; 53 float endY; 54 float subX; 55 float subY; 56 float limitX1; 57 float limitX2; 58 float limitY1; 59 float limitY2; 60 ICustomMethod mCustomMethod=null; 61 /** 62 * @param bitmap 要显示的图片 63 * @param contentW 内容区域宽度 64 * @param contentH 内容区域高度 65 * @param topHeight 状态栏高度和标题栏高度之和 66 * @param iCustomMethod 67 */ 68 public void imageInit(Bitmap bitmap,int contentW,int contentH,int topHeight,ICustomMethod iCustomMethod) 69 { 70 this.primaryBitmap=bitmap; 71 this.contentW=contentH; 72 this.contentH=contentH; 73 this.topHeight=topHeight; 74 mCustomMethod=iCustomMethod; 75 primaryW=primaryBitmap.getWidth(); 76 primaryH=primaryBitmap.getHeight(); 77 float scaleX=(float)contentW/primaryW; 78 float scaleY=(float)contentH/primaryH; 79 scale=scaleX<scaleY?scaleX:scaleY; 80 if (scale<1&&1/scale<bigScale) 81 { 82 bigScale=(float)(1/scale+0.5); 83 } 84 85 imgMatrix=new Matrix(); 86 subX = (contentW-primaryW*scale)/2; 87 subY=(contentH-primaryH*scale)/2; 88 this.setImageBitmap(primaryBitmap); 89 this.setScaleType(ScaleType.MATRIX); 90 imgMatrix.postScale(scale, scale); 91 imgMatrix.postTranslate(subX,subY); 92 this.setImageMatrix(imgMatrix); 93 } 94 /** 95 * 按下操作 96 * @param event 97 */ 98 public void mouseDown(MotionEvent event) 99 { 100 mode=NONE; 101 startX=event.getRawX(); 102 startY=event.getRawY(); 103 if (event.getPointerCount()==1) 104 { 105 //如果两次时间间隔小于一定值,则默认为双击事件 106 if (event.getEventTime()-lastClickTime<DOUBLE_CLICK_TIME_SPACE) 107 { 108 changeSize(startX,startY); 109 } 110 else if (isBig) 111 { 112 mode=DRAG; 113 } 114 } 115 lastClickTime=event.getEventTime(); 116 } 117 /** 118 * 非第一个点按下操作 119 * @param event 120 */ 121 public void mousePointDown(MotionEvent event) 122 { 123 startDistance=getDistance(event); 124 if (startDistance > DOUBLE_POINT_DISTANCE) { 125 mode = ZOOM; 126 } else { 127 mode = NONE; 128 } 129 } 130 public void mouseMove(MotionEvent event) 131 { 132 if ((mode == DRAG) && (isMoveX || isMoveY)) { 133 float[] XY = getTranslateXY(imgMatrix); 134 float transX = 0; 135 float transY = 0; 136 if (isMoveX) { 137 endX = event.getRawX(); 138 transX = endX - startX; 139 if ((XY[0] + transX) <= limitX1) { 140 transX = limitX1 - XY[0]; 141 } 142 if ((XY[0] + transX) >= limitX2) { 143 transX = limitX2 - XY[0]; 144 } 145 } 146 if (isMoveY) { 147 endY = event.getRawY(); 148 transY = endY - startY; 149 if ((XY[1] + transY) <= limitY1) { 150 transY = limitY1 - XY[1]; 151 } 152 if ((XY[1] + transY) >= limitY2) { 153 transY = limitY2 - XY[1]; 154 } 155 } 156 157 imgMatrix.postTranslate(transX, transY); 158 startX = endX; 159 startY = endY; 160 this.setImageMatrix(imgMatrix); 161 } else if (mode == ZOOM && event.getPointerCount() > 1) { 162 endDistance = getDistance(event); 163 float dif = endDistance - startDistance; 164 if (Math.abs(endDistance - startDistance) > DOUBLE_POINT_DISTANCE) { 165 if (isBig) { 166 if (dif < 0) { 167 changeSize(0, 0); 168 mode = NONE; 169 } 170 } else if (dif > 0) { 171 float x = event.getX(0) / 2 + event.getX(1) / 2; 172 float y = event.getY(0) / 2 + event.getY(1) / 2; 173 changeSize(x, y); 174 mode = NONE; 175 } 176 } 177 } 178 } 179 /** 180 * 鼠标抬起事件 181 */ 182 public void mouseUp() 183 { 184 mode = NONE; 185 } 186 private void changeSize(float x, float y) { 187 if (isBig) { 188 // 如果处于最大状态,则还原 189 imgMatrix.reset(); 190 imgMatrix.postScale(scale, scale); 191 imgMatrix.postTranslate(subX, subY); 192 isBig = false; 193 } else { 194 imgMatrix.postScale(bigScale, bigScale); // 在原有矩阵后乘放大倍数 195 float transX = -((bigScale - 1) * x); 196 float transY = -((bigScale - 1) * (y - topHeight)); // (bigScale-1)(y-statusBarHeight-subY)+2*subY; 197 float currentWidth = primaryW * scale * bigScale; // 放大后图片大小 198 float currentHeight = primaryH * scale * bigScale; 199 // 如果图片放大后超出屏幕范围处理 200 if (currentHeight > contentH) { 201 limitY1 = -(currentHeight - contentH); // 平移限制 202 limitY2 = 0; 203 isMoveY = true; // 允许在Y轴上拖动 204 float currentSubY = bigScale * subY; // 当前平移距离 205 // 平移后,内容区域上部有空白处理办法 206 if (-transY < currentSubY) { 207 transY = -currentSubY; 208 } 209 // 平移后,内容区域下部有空白处理办法 210 if (currentSubY + transY < limitY1) { 211 transY = -(currentHeight + currentSubY - contentH); 212 } 213 } else { 214 // 如果图片放大后没有超出屏幕范围处理,则不允许拖动 215 isMoveY = false; 216 } 217 218 if (currentWidth > contentW) { 219 limitX1 = -(currentWidth - contentW); 220 limitX2 = 0; 221 isMoveX = true; 222 float currentSubX = bigScale * subX; 223 if (-transX < currentSubX) { 224 transX = -currentSubX; 225 } 226 if (currentSubX + transX < limitX1) { 227 transX = -(currentWidth + currentSubX - contentW); 228 } 229 } else { 230 isMoveX = false; 231 } 232 233 imgMatrix.postTranslate(transX, transY); 234 isBig = true; 235 } 236 237 this.setImageMatrix(imgMatrix); 238 if (mCustomMethod != null) { 239 mCustomMethod.customMethod(isBig); 240 } 241 } 242 /** 243 * 获取变换矩阵中X轴偏移量和Y轴偏移量 244 * @param matrix 245 * @return 246 */ 247 private float[] getTranslateXY(Matrix matrix) 248 { 249 float[] values = new float[9]; 250 matrix.getValues(values); 251 float[] floats = new float[2]; 252 floats[0] = values[Matrix.MTRANS_X]; 253 floats[1] = values[Matrix.MTRANS_Y]; 254 return floats; 255 } 256 /** 257 * 获取两点间距离 258 * @param event 259 * @return 260 */ 261 private float getDistance(MotionEvent event) 262 { 263 float x = event.getX(0) - event.getX(1); 264 float y = event.getY(0) - event.getY(1); 265 return FloatMath.sqrt(x * x + y * y); 266 } 267 /** 268 * 用户自定义方法 269 * @author AILALA 270 */ 271 public interface ICustomMethod 272 { 273 public void customMethod(Boolean currentStatus); 274 } 275 }
测试布局:
1 <?xml version="1.0" encoding="utf-8"?> 2 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" 3 android:layout_width="match_parent" 4 android:layout_height="match_parent" > 5 6 <com.basecontrol.view.ImageControl 7 android:id="@+id/common_imageview_imageControll" 8 android:layout_width="fill_parent" 9 android:layout_height="fill_parent" 10 android:src="@drawable/ic_launcher"/> 11 12 <LinearLayout 13 android:id="@+id/common_iamgeview_llTitle" 14 android:layout_width="wrap_content" 15 android:layout_height="wrap_content" 16 android:layout_alignParentLeft="true" 17 android:layout_alignParentTop="true" > 18 19 <TextView 20 android:id="@+id/common_imageview_title" 21 android:layout_width="fill_parent" 22 android:layout_height="wrap_content" 23 android:text="报告"/> 24 </LinearLayout> 25 </RelativeLayout>
测试的Activity:
1 package com.basecontrol.ui; 2 3 import com.basecontrol.view.ImageControl; 4 import com.basecontrol.view.ImageControl.ICustomMethod; 5 import com.example.basecontrol.R; 6 import android.app.Activity; 7 import android.graphics.Bitmap; 8 import android.graphics.Rect; 9 import android.graphics.drawable.BitmapDrawable; 10 import android.os.Bundle; 11 import android.view.MotionEvent; 12 import android.view.View; 13 import android.widget.LinearLayout; 14 import android.widget.TextView; 15 import android.widget.Toast; 16 17 public class ImageViewActivity extends Activity 18 { 19 20 @Override 21 protected void onCreate(Bundle savedInstanceState) { 22 super.onCreate(savedInstanceState); 23 setContentView(R.layout.bc_common_image_view); 24 findView(); 25 } 26 27 public void onWindowFocusChanged(boolean hasFocus) 28 { 29 super.onWindowFocusChanged(hasFocus); 30 init(); 31 }; 32 33 ImageControl imgControl; 34 LinearLayout llTitle; 35 TextView tvTitle; 36 private void findView() 37 { 38 imgControl=(ImageControl) findViewById(R.id.common_imageview_imageControll); 39 llTitle=(LinearLayout) findViewById(R.id.common_iamgeview_llTitle); 40 tvTitle=(TextView) findViewById(R.id.common_imageview_title); 41 } 42 43 private void init() { 44 tvTitle.setText("图片测试"); 45 // 这里可以为imgcontrol的图片路径动态赋值 46 // ............ 47 48 Bitmap bmp; 49 if (imgControl.getDrawingCache() != null) { 50 bmp = Bitmap.createBitmap(imgControl.getDrawingCache()); 51 } else { 52 bmp = ((BitmapDrawable)imgControl.getDrawable()).getBitmap(); 53 } 54 Rect frame = new Rect(); 55 getWindow().getDecorView().getWindowVisibleDisplayFrame(frame); 56 int statusBarHeight = frame.top; 57 int screenW = this.getWindowManager().getDefaultDisplay().getWidth(); 58 int screenH = this.getWindowManager().getDefaultDisplay().getHeight() 59 - statusBarHeight; 60 if (bmp != null) { 61 imgControl.imageInit(bmp, screenW, screenH, statusBarHeight, 62 new ICustomMethod() { 63 @Override 64 public void customMethod(Boolean currentStatus) { 65 // 当图片处于放大或缩小状态时,控制标题是否显示 66 if (currentStatus) { 67 llTitle.setVisibility(View.GONE); 68 } else { 69 llTitle.setVisibility(View.VISIBLE); 70 } 71 } 72 }); 73 } 74 else 75 { 76 Toast.makeText(ImageViewActivity.this, "图片加载失败,请稍候再试!", Toast.LENGTH_SHORT) 77 .show(); 78 } 79 80 } 81 @Override 82 public boolean onTouchEvent(MotionEvent event) { 83 switch (event.getAction()&MotionEvent.ACTION_MASK) { 84 case MotionEvent.ACTION_DOWN: 85 imgControl.mouseDown(event); 86 break; 87 case MotionEvent.ACTION_POINTER_DOWN: 88 imgControl.mousePointDown(event); 89 break; 90 case MotionEvent.ACTION_MOVE: 91 imgControl.mouseMove(event); 92 break; 93 case MotionEvent.ACTION_UP: 94 imgControl.mouseUp(); 95 break; 96 } 97 return super.onTouchEvent(event); 98 } 99 }
嗯,就酱…………