我是靠谱客的博主 英俊手套,这篇文章主要介绍Android手势检测 带你打造支持图片缩放、平移预览(下),现在分享给大家,希望可以做个参考。

前面一片博客讲解和支持图片缩放的预览,但是那个缩放的缩放中心是固定的都是屏幕中心,这显然不能满足用户的需求,我们需要的是缩放焦点能够随着手势变化,还能够双击缩放,并且可以平移,本片博客就带大家来实现这些功能。这篇文章是基于 Android手势检测 带你打造图片缩放预览(上)的。


首先给出效果图:

贴出源代码,然后再对每个部分进行分析

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
class ScaleMoveImageViewer extends ImageView implements OnTouchListener,OnScaleGestureListener{ private ScaleGestureDetector sgc; private GestureDetector gd; private float SOURCE_SCALE; private Matrix matrix=new Matrix(); private float[] values=new float[9]; private boolean once=true; private float preX,preY,currentX,currentY; private int prePointerCount; private static final int REQUESTCODE_BIGER=1; private static final int REQUESTCODE_SMALLER=2; private static final float BIGER_TMP_SCALE=1.06f; private static final float SMALLER_TMP_SCALE=0.94f; private static final float MAX_SCALE=4.0F; private static final float MIN_SCALE=0.2F; public ScaleMoveImageViewer(Context context) { this(context,null); } public ScaleMoveImageViewer(Context context, AttributeSet attrs) { super(context, attrs); super.setScaleType(ScaleType.MATRIX); this.setOnTouchListener(this); sgc=new ScaleGestureDetector(context, this); gd=new GestureDetector(context, new SimpleOnGestureListener(){ @Override public boolean onDoubleTap(MotionEvent e) { Log.i("TAG","onDoubleTap"); float x=e.getX(); float y=e.getY(); setDobleTapScale(x, y); return true; } }); } //手指缩放 @Override public boolean onScale(ScaleGestureDetector detector) { float scaleFactor=detector.getScaleFactor(); float currentScale=getScale();//相对原图的缩放比例 if(currentScale>MAX_SCALE && scaleFactor<1.0f || currentScale<MIN_SCALE && scaleFactor>1.0f || currentScale<MAX_SCALE && currentScale>MIN_SCALE){ matrix.postScale(scaleFactor, scaleFactor, detector.getFocusX(), detector.getFocusY()); } ImagePositonManager.setShowPosition(getDrawable(), matrix, getWidth(), getHeight()); setImageMatrix(matrix); return true; } //移动 @Override public boolean onTouch(View v, MotionEvent event) { currentX=0;currentY=0; int pointerCount=event.getPointerCount(); for(int i=0;i<pointerCount;i++){ currentX+=event.getX(); currentY+=event.getY(); } currentX/=pointerCount; currentY/=pointerCount; if (pointerCount!=prePointerCount) { preX=currentX; preY=currentY; prePointerCount=pointerCount; } switch (event.getAction()) { case MotionEvent.ACTION_MOVE: float dx=currentX-preX; float dy=currentY-preY; ImagePositonManager.setMovePosition(getDrawable(), matrix, dx, dy, getWidth(), getHeight()); setImageMatrix(matrix); preX=currentX; preY=currentY; break; case MotionEvent.ACTION_UP://有多根手指触摸屏幕时,只有当所有的手指抬起时这里才执行 prePointerCount=0; break; } gd.onTouchEvent(event); return sgc.onTouchEvent(event); } //双击缩放 public void setDobleTapScale(float px,float py){ float currectScale=getScale(); if(currectScale<SOURCE_SCALE){ ScaleMoveImageViewer.this.postDelayed(new AutoScaleRunnable(SOURCE_SCALE, px, py,REQUESTCODE_BIGER), 10); } if(currectScale==SOURCE_SCALE){ ScaleMoveImageViewer.this.postDelayed(new AutoScaleRunnable(MAX_SCALE-1, px, py,REQUESTCODE_BIGER), 10); } if(currectScale>SOURCE_SCALE){ ScaleMoveImageViewer.this.postDelayed(new AutoScaleRunnable(SOURCE_SCALE, px, py,REQUESTCODE_SMALLER), 10); } ImagePositonManager.setShowPosition(getDrawable(), matrix, getWidth(), getHeight()); setImageMatrix(matrix); } private class AutoScaleRunnable implements Runnable{ float targetScale=0; float px=0; float py=0; int requestCode=0; public AutoScaleRunnable(float targetScale,float px,float py,int requestCode){ this.targetScale=targetScale; this.px=px; this.py=py; this.requestCode=requestCode; } @Override public void run() { if(requestCode==REQUESTCODE_BIGER){ matrix.postScale(BIGER_TMP_SCALE, BIGER_TMP_SCALE, px, py); ImagePositonManager.setShowPosition(getDrawable(), matrix, getWidth(), getHeight()); setImageMatrix(matrix); float currentScale = getScale(); if (currentScale<targetScale) { ScaleMoveImageViewer.this.postDelayed(this, 10); }else { while(getScale()!=targetScale){ matrix.postScale(targetScale/getScale(), targetScale/getScale(), px, py); ImagePositonManager.setShowPosition(getDrawable(), matrix, getWidth(), getHeight()); setImageMatrix(matrix); } } } else if (requestCode==REQUESTCODE_SMALLER) { matrix.postScale(SMALLER_TMP_SCALE, SMALLER_TMP_SCALE, px, py); ImagePositonManager.setShowPosition(getDrawable(), matrix, getWidth(), getHeight()); setImageMatrix(matrix); float currentScale = getScale(); if(currentScale>targetScale){ ScaleMoveImageViewer.this.postDelayed(this, 10); }else { while(getScale()!=targetScale){ matrix.postScale(targetScale/getScale(), targetScale/getScale(), px, py); ImagePositonManager.setShowPosition(getDrawable(), matrix, getWidth(), getHeight()); setImageMatrix(matrix); } } } } } @Override protected void onDraw(Canvas canvas) { if(once){ matrix=getImageMatrix(); once=false; Drawable drawable=getDrawable(); //获取图片的宽和高 int dw=drawable.getIntrinsicWidth(); int dh=drawable.getIntrinsicHeight(); int w=getWidth(); int h=getHeight(); float scale=Math.min(1.0f*w/dw, 1.0f*h/dh); SOURCE_SCALE=scale; matrix.postTranslate(w/2-dw/2, h/2-dh/2); matrix.postScale(scale, scale, w/2, h/2); setImageMatrix(matrix); } super.onDraw(canvas); } private float getScale(){ matrix.getValues(values); return values[Matrix.MSCALE_X]; } @Override public boolean onScaleBegin(ScaleGestureDetector detector) { return true; } @Override public void onScaleEnd(ScaleGestureDetector detector) { } }
第二部分工具类,来控制图片的位置
复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
public class ImagePositonManager { //缩放图片时控制其显示位置 public static void setShowPosition(Drawable drawable,Matrix matrix,int w,int h){ RectF rectF=new RectF(0, 0, drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight()); matrix.mapRect(rectF); float rw=rectF.width(); float rh=rectF.height(); float moveX=0,moveY=0; if(rw<=w){ moveX=w/2-rw/2-rectF.left; } if (rh<=h) { moveY=h/2-rh/2-rectF.top; } if(rw>w && rectF.left>0){ moveX=-rectF.left; } if(rw>w && rectF.right<w){ moveX=w-rectF.right; } if(rh>h && rectF.top>0){ moveY=-rectF.top; } if(rh>h && rectF.bottom<h){ moveY=h-rectF.bottom; } matrix.postTranslate(moveX, moveY); } //移动图片时控制显示位置 public static void setMovePosition(Drawable drawable,Matrix matrix,float dx,float dy,int w,int h){ RectF rectF=new RectF(0,0,drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight()); matrix.mapRect(rectF); float rw=rectF.width(); float rh=rectF.height(); if(rw>w && rectF.left+dx<=0 && rectF.right+dx>=w){ matrix.postTranslate(dx, 0); } if(rh>h && rectF.top+dy<=0 && rectF.bottom+dy>=h){ matrix.postTranslate(0, dy); } } }


最后就是主函数和布局文件,这个很简单不贴代码了

现在对每个部分进行分析
复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
//移动 @Override public boolean onTouch(View v, MotionEvent event) { currentX=0;currentY=0; int pointerCount=event.getPointerCount(); for(int i=0;i<pointerCount;i++){ currentX+=event.getX(); currentY+=event.getY(); } currentX/=pointerCount; currentY/=pointerCount; if (pointerCount!=prePointerCount) { preX=currentX; preY=currentY; prePointerCount=pointerCount; } switch (event.getAction()) { case MotionEvent.ACTION_MOVE: float dx=currentX-preX; float dy=currentY-preY; ImagePositonManager.setMovePosition(getDrawable(), matrix, dx, dy, getWidth(), getHeight()); setImageMatrix(matrix); preX=currentX; preY=currentY; break; case MotionEvent.ACTION_UP://有多根手指触摸屏幕时,只有当所有的手指抬起时这里才执行 prePointerCount=0; break; } gd.onTouchEvent(event); return sgc.onTouchEvent(event); }
关于图片的移动,代码挺简单相信大家都能看的懂,但是有几点需要注意的地方
1、图片的一定是一个多点操作,所以触摸点的位置我们去所有手指位置的平均值
2、要特别注意这段代码
if (pointerCount!=prePointerCount) {
preX=currentX;
preY=currentY;
prePointerCount=pointerCount;
}当触摸点的数量发生变化时,即有手指抬起或按下时,这是我们为了保证图片不移动,需要将前一次的x,y值赋值为当前的x,y值。如果不这样做,当我们的手放在屏幕上不动,r然后突然抬起(按下)一根手指,这是照片就会移动。

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
public void setDobleTapScale(float px,float py){ float currectScale=getScale(); if(currectScale<SOURCE_SCALE){ ScaleMoveImageViewer.this.postDelayed(new AutoScaleRunnable(SOURCE_SCALE, px, py,REQUESTCODE_BIGER), 10); } if(currectScale==SOURCE_SCALE){ ScaleMoveImageViewer.this.postDelayed(new AutoScaleRunnable(MAX_SCALE-1, px, py,REQUESTCODE_BIGER), 10); } if(currectScale>SOURCE_SCALE){ ScaleMoveImageViewer.this.postDelayed(new AutoScaleRunnable(SOURCE_SCALE, px, py,REQUESTCODE_SMALLER), 10); } ImagePositonManager.setShowPosition(getDrawable(), matrix, getWidth(), getHeight()); setImageMatrix(matrix); } private class AutoScaleRunnable implements Runnable{ float targetScale=0; float px=0; float py=0; int requestCode=0; public AutoScaleRunnable(float targetScale,float px,float py,int requestCode){ this.targetScale=targetScale; this.px=px; this.py=py; this.requestCode=requestCode; } @Override public void run() { if(requestCode==REQUESTCODE_BIGER){ matrix.postScale(BIGER_TMP_SCALE, BIGER_TMP_SCALE, px, py); ImagePositonManager.setShowPosition(getDrawable(), matrix, getWidth(), getHeight()); setImageMatrix(matrix); float currentScale = getScale(); if (currentScale<targetScale) { ScaleMoveImageViewer.this.postDelayed(this, 10); }else { while(getScale()!=targetScale){ matrix.postScale(targetScale/getScale(), targetScale/getScale(), px, py); ImagePositonManager.setShowPosition(getDrawable(), matrix, getWidth(), getHeight()); setImageMatrix(matrix); } } } else if (requestCode==REQUESTCODE_SMALLER) { matrix.postScale(SMALLER_TMP_SCALE, SMALLER_TMP_SCALE, px, py); ImagePositonManager.setShowPosition(getDrawable(), matrix, getWidth(), getHeight()); setImageMatrix(matrix); float currentScale = getScale(); if(currentScale>targetScale){ ScaleMoveImageViewer.this.postDelayed(this, 10); }else { while(getScale()!=targetScale){ matrix.postScale(targetScale/getScale(), targetScale/getScale(), px, py); ImagePositonManager.setShowPosition(getDrawable(), matrix, getWidth(), getHeight()); setImageMatrix(matrix); } } } } }
双击缩放,不能突然一下子就变大或变小,这样用户体验效果很差,所以我们做成了一个动画效果,这里我们主要来讲解AutoScaleRunnable,当用户双击图片后,
AutoScaleRunnable 会执行,注意我们matrix.postScale(BIGER_TMP_SCALE, BIGER_TMP_SCALE, px, py);BIGER_TMP_SCALE=是一个接近1  比1大一点的数,所以我们每一次都是只缩放一点点,通过反复的执行run方法就达到了缩放到最终目标大小targetScale,如何反复呢,我们通过这句代码来实现
if (currentScale<targetScale) {
ScaleMoveImageViewer.this.postDelayed(this, 10);
}

代码分析到这里已经结束了!








最后

以上就是英俊手套最近收集整理的关于Android手势检测 带你打造支持图片缩放、平移预览(下)的全部内容,更多相关Android手势检测内容请搜索靠谱客的其他文章。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(56)

评论列表共有 0 条评论

立即
投稿
返回
顶部