听说写博客可以丰富简历?好吧,正好无聊,我也写写看~
先放上一张效果图:
在这里,我对自己的笔记本全屏截图,然后当作自定义ImageView的
src内容放在真机上运行。
可以看到这里的图片是可以移动和缩放的。
在这里先说清一点,如果在xml的控件上设置src,则需要在代码上
通过getDrawable();获取,如果是通过setBackGround的,则通过
getBackground();获取即可。
1. public class MyImageView extends ImageView implements ScaleGestureDetector.OnScaleGestureListener,
2. View.OnTouchListener {
这个是我自定义ImageView的类名。
我在这里实现了一些待会会用到的接口。
1. /**
2. * 控件宽度
3. */
4. private int mWidth;
5. /**
6. * 控件高度
7. */
8. private int mHeight;
9. /**
10. * 拿到src的图片
11. */
12. private Drawable mDrawable;
13. /**
14. * 图片宽度(使用前判断mDrawable是否null)
15. */
16. private int mDrawableWidth;
17. /**
18. * 图片高度(使用前判断mDrawable是否null)
19. */
20. private int mDrawableHeight;
21.
22. /**
23. * 初始化缩放值
24. */
25. private float mScale;
26.
27. /**
28. * 双击图片的缩放值
29. */
30. private float mDoubleClickScale;
31.
32. /**
33. * 最大的缩放值
34. */
35. private float mMaxScale;
36.
37. /**
38. * 最小的缩放值
39. */
40. private float mMinScale;
41.
42. private ScaleGestureDetector scaleGestureDetector;
43. /**
44. * 当前有着缩放值、平移值的矩阵。
45. */
46. private Matrix matrix;
这些是我定义出来的一些成员变量,每个变量我都写上了作用。
1. public MyImageView(Context context) {
2. this(context, null);
3. }
4.
5. public MyImageView(Context context, AttributeSet attrs) {
6. this(context, attrs, 0);
7. }
8.
9. public MyImageView(Context context, AttributeSet attrs, int defStyleAttr) {
10. super(context, attrs, defStyleAttr);
11. this);
12. new ScaleGestureDetector(context, this);
13. initListener();
14. }
这里是三个标准的构造器,直接用短的引用长的就是了。
先看一看initListener();干了什么事情。
1. /**
2. * 初始化事件监听
3. */
4. private void initListener() {
5. // 强制设置模式
6. setScaleType(ScaleType.MATRIX);
7. // 添加观察者
8. new ViewTreeObserver.OnGlobalLayoutListener() {
9. @Override
10. public void onGlobalLayout() {
11. // 移除观察者
12. this);
13. // 获取控件大小
14. mWidth = getWidth();
15. mHeight = getHeight();
16.
17. //通过getDrawable获得Src的图片
18. mDrawable = getDrawable();
19. if (mDrawable == null)
20. return;
21. mDrawableWidth = mDrawable.getIntrinsicWidth();
22. mDrawableHeight = mDrawable.getIntrinsicHeight();
23. initImageViewSize();
24. moveToCenter();
25. }
26. });
27. }
这里唯一要注意的是我在初始化监听这个方法内,强制了ImageView的scaleType
模式为:MATRIX,因为等会会用到矩阵来缩放和平移,因此强制一下它的scaleT-
ype。
initImageViewSize();这个方法,光看名字就知道要初始化图片大小,来看一看怎么
样去初始化的。
1. /**
2. * 初始化资源图片宽高
3. */
4. private void initImageViewSize() {
5. if (mDrawable == null)
6. return;
7.
8. // 缩放值
9. float scale = 1.0f;
10. // 图片宽度大于控件宽度,图片高度小于控件高度
11. if (mDrawableWidth > mWidth && mDrawableHeight < mHeight)
12. 1.0f / mDrawableWidth;
13. // 图片高度度大于控件宽高,图片宽度小于控件宽度
14. else if (mDrawableHeight > mHeight && mDrawableWidth < mWidth)
15. 1.0f / mDrawableHeight;
16. // 图片宽度大于控件宽度,图片高度大于控件高度
17. else if (mDrawableHeight > mHeight && mDrawableWidth > mWidth)
18. 1.0f / mDrawableHeight, mWidth * 1.0f / mDrawableWidth);
19. // 图片宽度小于控件宽度,图片高度小于控件高度
20. else if (mDrawableHeight < mHeight && mDrawableWidth < mWidth)
21. 1.0f / mDrawableHeight, mWidth * 1.0f / mDrawableWidth);
22. mScale = scale;
23. 8.0f;
24. 0.5f;
25. }
先判断一下有没有src资源,没有的话,这个方法调用也没意义了。
这里是要图片的宽或高其中一边充满着屏幕,在最后的三句话,意思就是,
首先,我们假设初始化缩放后的图片面积是A,允许它的最大放大倍数为8A,
最小缩小倍数为0.5A,就是这个意思,(是基于初始化缩放后的面积,而不是
原图的面积,想想这是笔记本的屏幕面积,很大吧!)
moveToCenter();这个方法之前,先看一下不调用这个方法的效果图会咋样。
scaleType为MATRIX属性的图片都是不经过缩放直接显示在屏幕左上角,
这时候肯定会有童鞋问,咦,刚刚不是缩放过么,我这时候只能说,孩子,
你太天真了,那只是理论上的缩放值,还没经过实操呢(滑稽)
。
好吧,接下来就看看moveToCenter();做了什么事情,
1. /**
2. * 移动控件中间位置
3. */
4. private void moveToCenter() {
5. final float dx = mWidth / 2 - mDrawableWidth / 2;
6. final float dy = mHeight / 2 - mDrawableHeight / 2;
7. new Matrix();
8. // 平移至中心
9. matrix.postTranslate(dx, dy);
10. // 以控件中心作为缩放
11. 2, mHeight / 2);
12. setImageMatrix(matrix);
13. }
看注释的意思是要把它(图片)移动到屏幕的正中心,
dx的意思是取横方向上,控件中心到图片中心的值,如果大于0就向右移动,
反之向左移动相应的绝对值。
dy则换成纵向方向就是了。
在这里实例化了matrix对象(初始化一次就行),至于为什么只需要初始化一次,
因为图片的缩放值和平移值,都是通过matrix保存的,如果再一次初始化,缩放值
和平移值等等数据都会被清空。
我是先让它平时到控件正中心,然后以控件中心缩放mScale,mScale在initImageViewSize();的时候已经赋值了。
至于先缩放后平移,应该也是可以得,但可能计算公式相对麻烦些,
在这里本着方便为主的原则,就不再作计算了。
接下来会说到这个东西scaleGestureDetector = new ScaleGestureDetector(context, this);
通过这个方法,实现了监听事件,是手势滑动的监听事件。
1. @Override
2. public boolean onScale(ScaleGestureDetector detector) {
3.
4. return true;
5. }
6.
7.
8. @Override
9. public boolean onScaleBegin(ScaleGestureDetector detector) {
10. return true;
11. }
12.
13. @Override
14. public void onScaleEnd(ScaleGestureDetector detector) {
15.
16. }
但是,虽然实现了监听,但是然并卵,因为onTouch事件中没有它(scaleGestureDetector),在这里 ,重写onTouchEvent是没用的,因为onTouchEventListener的优先级比
onTouchEvent要高,所以我们只能这样子。
1. setOnTouchListener(this);
1. @Override
2. public boolean onTouch(View v, MotionEvent event) {
3.
4. return scaleGestureDetector.onTouchEvent(event);
5. }
在最后调用了scaleGestureDetector.onTouchEvent(event);这个方法。
然后手势生效了(呵呵哒
)。
1. @Override
2. public boolean onScaleBegin(ScaleGestureDetector detector) {
3. return true;
4. }
这个方法是手势执行前生效,必须return ture, 不然onScale必定失效
!
现在重点说一下onScale,因为这个方法是处理手势的缩放,
1. @Override
2. public boolean onScale(ScaleGestureDetector detector) {
3. if (mDrawable == null) {
4. return true;
5. }
6. // 系统定义的缩放值
7. float scaleFactor = detector.getScaleFactor();
8. // 获取已经缩放的值
9. float scale = getmScale();
10. float scaleResult = scale * scaleFactor;
11. if (scaleResult >= mMaxScale && scaleFactor > 1.0f)
12. scaleFactor = mMaxScale / scale;
13. if (scaleResult <= mMinScale && scaleFactor < 1.0f)
14. scaleFactor = mMinScale / scale;
15.
16.
17. matrix.postScale(scaleFactor, scaleFactor, detector.getFocusX(), detector.getFocusY());
18.
19. /。。。
1. <span style="white-space:pre"> setImageMatrix(matrix);</span>
2. }
其中,scaleFactor是获得手势缩放的值(具体怎么获取的不知道),当值>1.0f时,说明两个手指的滑动距离是不断增加(相对于两个手指都down了的那一瞬间),同理<1.0f说明两个手指的滑动距离不断减少,也是相对于那一瞬间,
1. /**
2. * @return 当前缩放的值
3. */
4. private float getmScale() {
5. float[] floats = new float[9];
6. matrix.getValues(floats);
7. return floats[Matrix.MSCALE_X];
8. }
通过这个方法 ,拿到了之前matrix对象的scaleX值( X和Y都没所谓,因为在这里都是一个值
),然后将当前的scale*手势滑动的缩放值,得到最新的缩放值scaleResult,在这里做了一个最大放大值和最小缩小值得处理,如果
scaleResult大于等于最大缩放值和手指滑动为放大手势,则让手势缩放为一个恒定的最大放大值(反之同理)。
看效果图后,会觉得比较奇葩,因为缩小的时候,位置好像偏了!(原本是在控件正中心)。
1. /**
2. * @param matrix 矩阵
3. * @return matrix的 l t b r 和width,height
4. */
5. private RectF getRectf(Matrix matrix) {
6. new RectF();
7. if (mDrawable == null)
8. return null;
9. 0, 0, mDrawableWidth, mDrawableHeight);
10. matrix.mapRect(f);
11. return f;
12. }
首先看一下这个方法,通过这个方法,可以得到矩阵matrix的N维属性,并把这N维属性赋值到一个float类型的矩形上。
在将上面的/。。。补上
1. <span style="white-space:pre"> </span>RectF f = getRectf(matrix);
2. float dX = 0.0f;
3. float dY = 0.0f;
4. // 图片高度大于控件高度
5. if (f.height() >= mHeight) {
6. // 图片顶部出现空白
7. if (f.top > 0) {
8. // 往上移动
9. dY = -f.top;
10. }
11. // 图片底部出现空白
12. if (f.bottom < mHeight) {
13. // 往下移动
14. dY = mHeight - f.bottom;
15. }
16. }
17. // 图片宽度大于控件宽度
18. if (f.width() >= mWidth) {
19. // 图片左边出现空白
20. if (f.left > 0) {
21. // 往左边移动
22. dX = -f.left;
23. }
24. // 图片右边出现空白
25. if (f.right < mWidth) {
26. // 往右边移动
27. dX = mWidth - f.right;
28. }
29. }
30.
31. if (f.width() < mWidth) {
32. 2 - f.right + f.width() / 2;
33. }
34.
35. if (f.height() < mHeight) {
36. 2 - f.bottom + f.height() / 2;
37. }
38. matrix.postTranslate(dX, dY);
39. setImageMatrix(matrix);
首先获取矩阵matrix的N维并赋值在f身上。
在这里其实是细分为2种情况(横竖类似的合一)
以纵向为例:
1. // 图片高度大于控件高度
2. if (f.height() >= mHeight) {
3. // 图片顶部出现空白
4. if (f.top > 0) {
5. // 往上移动
6. dY = -f.top;
7. }
8. // 图片底部出现空白
9. if (f.bottom < mHeight) {
10. // 往下移动
11. dY = mHeight - f.bottom;
12. }
13. }
大概就是这个意思:当图片高度大于等于控件高度的时候,坚决不让控件高度方向上出现白色位置,此时,假设当图片和控件高度完全相同的时候,是不是图片的纵向刚好和控件完全重叠呢?
再看第二种情况:
1. if (f.height() < mHeight) {
2. 2 - f.bottom + f.height() / 2;
3. }
之前说到,当图片和控件高度完全相同的时候,是不是图片的纵向刚好和控件完全重叠呢?其实,这句话不应该用假设句,而是肯定句,所以,想想,如果图片纵向恰好小于控件高度那么一点点,是不是图片纵向上瞬间就被移动到控件的中间呢?
这种情况的横向方向的道理完全一致,在此也说明一个道理,可以把复杂的事情细分了处理,反正方法是顺着执行的。
这样,图片的缩放就处理完了。
现在说一下移动图片:
1. private float downX;
2. private float downY;
3. private float nowMovingX;
4. private float nowMovingY;
5. private float lastMovedX;
6. private float lastMovedY;
7. private boolean isFirstMoved = false;
8.
9. @Override
10. public boolean onTouch(View v, MotionEvent event) {
11. switch (event.getAction() & MotionEvent.ACTION_MASK) {
12. case MotionEvent.ACTION_DOWN:
13. false;
14. downX = event.getX();
15. downY = event.getY();
16. break;
17. case MotionEvent.ACTION_POINTER_DOWN:
18. false;
19. break;
20. case MotionEvent.ACTION_MOVE:
21. nowMovingX = event.getX();
22. nowMovingY = event.getY();
23. if (!isFirstMoved) {
24. true;
25. lastMovedX = nowMovingX;
26. lastMovedY = nowMovingY;
27. }
28. float dX = 0.0f;
29. float dY = 0.0f;
30. RectF rectf = getRectf(matrix);
31. // 判断滑动方向
32. final float scrollX = nowMovingX - lastMovedX;
33. // 判断滑动方向
34. final float scrollY = nowMovingY - lastMovedY;
35. // 图片高度大于控件高度
36. if (rectf.height() > mHeight && canSmoothY()) {
37. dY = nowMovingY - lastMovedY;
38. }
39.
40. // 图片宽度大于控件宽度
41. if (rectf.width() > mWidth && canSmoothX()) {
42. dX = nowMovingX - lastMovedX;
43. }
44. matrix.postTranslate(dX, dY);
45.
46. remedyXAndY(dX,dY);
47.
48. lastMovedX = nowMovingX;
49. lastMovedY = nowMovingY;
50. break;
51. case MotionEvent.ACTION_UP:
52. break;
53. case MotionEvent.ACTION_POINTER_UP:
54. false;
55. break;
56. }
57. return scaleGestureDetector.onTouchEvent(event);
58. }
MotionEvent.ACTION_POINTER_DOWN;这个也是压下的时候,区别在于只有不是第一根手指压下的时候才执行,
所以,我在压下的动作都初始化isFirstMoved=false;
当移动的时候,ACTION_MOVE也会执行。
由于移动的时候处理逻辑少的问题,出现屏幕越界后明显的白边反弹,因此在这里编辑了一部分代码。。。
滑动前,先判断能否滑动,滑动后,再次判断是否越界,因此,有效解决了白边反弹现象。
1. /**
2. * 判断x方向上能不能滑动
3. * @return 可以滑动返回true
4. */
5. private boolean canSmoothX(){
6. RectF rectf = getRectf(matrix);
7. if (rectf.left >0 || rectf.right <getWidth())
8. return false;
9. return true;
10. }
11.
12. /**
13. * 判断y方向上可不可以滑动
14. * @return 可以滑动返回true
15. */
16. private boolean canSmoothY(){
17. RectF rectf = getRectf(matrix);
18. if (rectf.top>0 || rectf.bottom < getHeight())
19. return false;
20. return true;
21. }
以上是x和y方向上,滑动前判断可不可以滑动的片段代码。
1. /**
2. * 纠正出界的横和众线
3. * @param dx 出界偏移的横线
4. * @param dy 出街便宜的众线
5. */
6. private void remedyXAndY(float dx,float dy){
7. if (!canSmoothX())
8. 0);
9. if (!canSmoothY())
10. 0,-dy);
11. setImageMatrix(matrix);
12. }
这段是用于滑动之后判断是否越界的,如果越界,把多余的dx和dy滑动回去。
完整的自定义控件代码:
1. package com.test.gesturedemo.view;
2.
3. import android.content.Context;
4. import android.graphics.Matrix;
5. import android.graphics.RectF;
6. import android.graphics.drawable.Drawable;
7. import android.util.AttributeSet;
8. import android.view.MotionEvent;
9. import android.view.ScaleGestureDetector;
10. import android.view.View;
11. import android.view.ViewTreeObserver;
12. import android.widget.ImageView;
13.
14. /**
15. * Created by 13798 on 2016/6/3.
16. */
17. public class MyImageView extends ImageView implements ScaleGestureDetector.OnScaleGestureListener, View.OnTouchListener {
18. /**
19. * 控件宽度
20. */
21. private int mWidth;
22. /**
23. * 控件高度
24. */
25. private int mHeight;
26. /**
27. * 拿到src的图片
28. */
29. private Drawable mDrawable;
30. /**
31. * 图片宽度(使用前判断mDrawable是否null)
32. */
33. private int mDrawableWidth;
34. /**
35. * 图片高度(使用前判断mDrawable是否null)
36. */
37. private int mDrawableHeight;
38.
39. /**
40. * 初始化缩放值
41. */
42. private float mScale;
43.
44. /**
45. * 双击图片的缩放值
46. */
47. private float mDoubleClickScale;
48.
49. /**
50. * 最大的缩放值
51. */
52. private float mMaxScale;
53.
54. /**
55. * 最小的缩放值
56. */
57. private float mMinScale;
58.
59. private ScaleGestureDetector scaleGestureDetector;
60. /**
61. * 当前有着缩放值、平移值的矩阵。
62. */
63. private Matrix matrix;
64.
65. public MyImageView(Context context) {
66. this(context, null);
67. }
68.
69. public MyImageView(Context context, AttributeSet attrs) {
70. this(context, attrs, 0);
71. }
72.
73. public MyImageView(Context context, AttributeSet attrs, int defStyleAttr) {
74. super(context, attrs, defStyleAttr);
75. this);
76. new ScaleGestureDetector(context, this);
77. initListener();
78. }
79.
80.
81. /**
82. * 初始化事件监听
83. */
84. private void initListener() {
85. // 强制设置模式
86. setScaleType(ScaleType.MATRIX);
87. // 添加观察者
88. new ViewTreeObserver.OnGlobalLayoutListener() {
89. @Override
90. public void onGlobalLayout() {
91. // 移除观察者
92. this);
93. // 获取控件大小
94. mWidth = getWidth();
95. mHeight = getHeight();
96.
97. //通过getDrawable获得Src的图片
98. mDrawable = getDrawable();
99. if (mDrawable == null)
100. return;
101. mDrawableWidth = mDrawable.getIntrinsicWidth();
102. mDrawableHeight = mDrawable.getIntrinsicHeight();
103. initImageViewSize();
104. moveToCenter();
105. }
106. });
107. }
108.
109. /**
110. * 初始化资源图片宽高
111. */
112. private void initImageViewSize() {
113. if (mDrawable == null)
114. return;
115.
116. // 缩放值
117. float scale = 1.0f;
118. // 图片宽度大于控件宽度,图片高度小于控件高度
119. if (mDrawableWidth > mWidth && mDrawableHeight < mHeight)
120. 1.0f / mDrawableWidth;
121. // 图片高度度大于控件宽高,图片宽度小于控件宽度
122. else if (mDrawableHeight > mHeight && mDrawableWidth < mWidth)
123. 1.0f / mDrawableHeight;
124. // 图片宽度大于控件宽度,图片高度大于控件高度
125. else if (mDrawableHeight > mHeight && mDrawableWidth > mWidth)
126. 1.0f / mDrawableHeight, mWidth * 1.0f / mDrawableWidth);
127. // 图片宽度小于控件宽度,图片高度小于控件高度
128. else if (mDrawableHeight < mHeight && mDrawableWidth < mWidth)
129. 1.0f / mDrawableHeight, mWidth * 1.0f / mDrawableWidth);
130. mScale = scale;
131. 8.0f;
132. 0.5f;
133. }
134.
135. /**
136. * 移动控件中间位置
137. */
138. private void moveToCenter() {
139. final float dx = mWidth / 2 - mDrawableWidth / 2;
140. final float dy = mHeight / 2 - mDrawableHeight / 2;
141. new Matrix();
142. // 平移至中心
143. matrix.postTranslate(dx, dy);
144. // 以控件中心作为缩放
145. 2, mHeight / 2);
146. setImageMatrix(matrix);
147. }
148.
149. /**
150. * @return 当前缩放的值
151. */
152. private float getmScale() {
153. float[] floats = new float[9];
154. matrix.getValues(floats);
155. return floats[Matrix.MSCALE_X];
156. }
157.
158. /**
159. * @param matrix 矩阵
160. * @return matrix的 l t b r 和width,height
161. */
162. private RectF getRectf(Matrix matrix) {
163. new RectF();
164. if (mDrawable == null)
165. return null;
166. 0, 0, mDrawableWidth, mDrawableHeight);
167. matrix.mapRect(f);
168. return f;
169. }
170.
171. @Override
172. public boolean onScale(ScaleGestureDetector detector) {
173. if (mDrawable == null) {
174. return true;
175. }
176. // 系统定义的缩放值
177. float scaleFactor = detector.getScaleFactor();
178. // 获取已经缩放的值
179. float scale = getmScale();
180. float scaleResult = scale * scaleFactor;
181. if (scaleResult >= mMaxScale && scaleFactor > 1.0f)
182. scaleFactor = mMaxScale / scale;
183. if (scaleResult <= mMinScale && scaleFactor < 1.0f)
184. scaleFactor = mMinScale / scale;
185.
186. matrix.postScale(scaleFactor, scaleFactor, detector.getFocusX(), detector.getFocusY());
187.
188. RectF f = getRectf(matrix);
189. float dX = 0.0f;
190. float dY = 0.0f;
191. // 图片高度大于控件高度
192. if (f.height() >= mHeight) {
193. // 图片顶部出现空白
194. if (f.top > 0) {
195. // 往上移动
196. dY = -f.top;
197. }
198. // 图片底部出现空白
199. if (f.bottom < mHeight) {
200. // 往下移动
201. dY = mHeight - f.bottom;
202. }
203. }
204. // 图片宽度大于控件宽度
205. if (f.width() >= mWidth) {
206. // 图片左边出现空白
207. if (f.left > 0) {
208. // 往左边移动
209. dX = -f.left;
210. }
211. // 图片右边出现空白
212. if (f.right < mWidth) {
213. // 往右边移动
214. dX = mWidth - f.right;
215. }
216. }
217.
218. if (f.width() < mWidth) {
219. 2 - f.right + f.width() / 2;
220. }
221.
222. if (f.height() < mHeight) {
223. 2 - f.bottom + f.height() / 2;
224. }
225. matrix.postTranslate(dX, dY);
226. setImageMatrix(matrix);
227. return true;
228. }
229.
230.
231. @Override
232. public boolean onScaleBegin(ScaleGestureDetector detector) {
233. return true;
234. }
235.
236. @Override
237. public void onScaleEnd(ScaleGestureDetector detector) {
238. float scale = getmScale();
239. if (scale < mScale) {
240. 2, mHeight / 2);
241. setImageMatrix(matrix);
242. }
243. }
244.
245.
246. private float downX;
247. private float downY;
248. private float nowMovingX;
249. private float nowMovingY;
250. private float lastMovedX;
251. private float lastMovedY;
252. private boolean isFirstMoved = false;
253.
254. @Override
255. public boolean onTouch(View v, MotionEvent event) {
256. switch (event.getAction() & MotionEvent.ACTION_MASK) {
257. case MotionEvent.ACTION_DOWN:
258. false;
259. downX = event.getX();
260. downY = event.getY();
261. break;
262. case MotionEvent.ACTION_POINTER_DOWN:
263. false;
264. break;
265. case MotionEvent.ACTION_MOVE:
266. nowMovingX = event.getX();
267. nowMovingY = event.getY();
268. if (!isFirstMoved) {
269. true;
270. lastMovedX = nowMovingX;
271. lastMovedY = nowMovingY;
272. }
273. float dX = 0.0f;
274. float dY = 0.0f;
275. RectF rectf = getRectf(matrix);
276. // 判断滑动方向
277. final float scrollX = nowMovingX - lastMovedX;
278. // 判断滑动方向
279. final float scrollY = nowMovingY - lastMovedY;
280. // 图片高度大于控件高度
281. if (rectf.height() > mHeight && canSmoothY()) {
282. dY = nowMovingY - lastMovedY;
283. }
284.
285. // 图片宽度大于控件宽度
286. if (rectf.width() > mWidth && canSmoothX()) {
287. dX = nowMovingX - lastMovedX;
288. }
289. matrix.postTranslate(dX, dY);
290.
291. remedyXAndY(dX,dY);
292.
293. lastMovedX = nowMovingX;
294. lastMovedY = nowMovingY;
295. break;
296. case MotionEvent.ACTION_UP:
297. break;
298. case MotionEvent.ACTION_POINTER_UP:
299. false;
300. break;
301. }
302. return scaleGestureDetector.onTouchEvent(event);
303. }
304.
305. /**
306. * 判断x方向上能不能滑动
307. * @return 可以滑动返回true
308. */
309. private boolean canSmoothX(){
310. RectF rectf = getRectf(matrix);
311. if (rectf.left >0 || rectf.right <getWidth())
312. return false;
313. return true;
314. }
315.
316. /**
317. * 判断y方向上可不可以滑动
318. * @return 可以滑动返回true
319. */
320. private boolean canSmoothY(){
321. RectF rectf = getRectf(matrix);
322. if (rectf.top>0 || rectf.bottom < getHeight())
323. return false;
324. return true;
325. }
326.
327. /**
328. * 纠正出界的横和众线
329. * @param dx 出界偏移的横线
330. * @param dy 出街便宜的众线
331. */
332. private void remedyXAndY(float dx,float dy){
333. if (!canSmoothX())
334. 0);
335. if (!canSmoothY())
336. 0,-dy);
337. setImageMatrix(matrix);
338. }
339. }
activity的xml
1. <?xml version="1.0" encoding="utf-8"?>
2. <RelativeLayout
3. xmlns:android="http://schemas.android.com/apk/res/android"
4. xmlns:tools="http://schemas.android.com/tools"
5. android:layout_width="match_parent"
6. android:layout_height="match_parent">
7.
8. <com.test.gesturedemo.view.MyImageView
9. android:layout_width="match_parent"
10. android:layout_height="match_parent"
11. android:scaleType="matrix"
12. android:src="@mipmap/tt1"/>
13.
14. </RelativeLayout>