1414import android .graphics .RectF ;
1515import android .graphics .Region ;
1616import android .support .annotation .DrawableRes ;
17+ import android .support .annotation .Nullable ;
18+ import android .support .v4 .view .MotionEventCompat ;
1719import android .support .v7 .widget .AppCompatImageView ;
1820import android .util .AttributeSet ;
1921import android .view .MotionEvent ;
2022
2123import java .util .ArrayList ;
22-
24+ import java .util .Collections ;
25+ /**
26+ * Author: miaoyongjun
27+ * Date : 17/8/1
28+ */
2329
2430public class StickerView extends AppCompatImageView {
2531
@@ -174,12 +180,17 @@ private void drawBtn(Sticker sticker, Canvas canvas) {
174180 public boolean onTouchEvent (MotionEvent event ) {
175181 float evX = event .getX (0 );
176182 float evY = event .getY (0 );
177-
178- switch (event . getAction () ) {
183+ int action = MotionEventCompat . getActionMasked ( event );
184+ switch (action ) {
179185 case MotionEvent .ACTION_POINTER_DOWN :
180- //然并卵的代码
181- evX = event .getX (event .getPointerCount () - 1 );
182- evY = event .getY (event .getPointerCount () - 1 );
186+ midPoint = calculateMidPoint (event );
187+ oldDistance = StickerUtil .calculateDistance (event );
188+ oldRotation = StickerUtil .calculateRotation (event );
189+ if (touchInsideSticker (event .getX (0 ), event .getY (0 ))
190+ && touchInsideSticker (event .getX (1 ), event .getY (1 ))) {
191+ state = TouchState .DOUBLE_TOUCH ;
192+ }
193+ break ;
183194 case MotionEvent .ACTION_DOWN :
184195 if (touchInsideDeleteButton (evX , evY )) {
185196 state = TouchState .PRESS_DELETE ;
@@ -194,13 +205,17 @@ public boolean onTouchEvent(MotionEvent event) {
194205 } else {
195206 state = TouchState .TOUCHING_OUTSIDE ;
196207 }
208+
197209 break ;
198210 case MotionEvent .ACTION_MOVE :
199211 float dx = evX - lastPoint .x ;
200212 float dy = evY - lastPoint .y ;
201213 if (state == TouchState .PRESS_SCALE_AND_ROTATE ) {
202214 rotateAndScale (evX , evY );
203215 }
216+ if (state == TouchState .DOUBLE_TOUCH ) {
217+ rotateAndScaleDoubleTouch (event );
218+ }
204219 if (state == TouchState .TOUCHING_INSIDE ) {
205220 translate (dx , dy );
206221 }
@@ -221,40 +236,99 @@ public boolean onTouchEvent(MotionEvent event) {
221236 invalidate ();
222237 }
223238 break ;
239+ case MotionEvent .ACTION_POINTER_UP :
240+ oldDistance = 0 ;
241+ oldRotation = 0 ;
242+ break ;
224243 }
225244 lastPoint .x = evX ;
226245 lastPoint .y = evY ;
227246 return true ;
228247 }
229248
249+ private void rotateAndScaleDoubleTouch (MotionEvent event ) {
250+ if (event .getPointerCount () < 2 ) {
251+ return ;
252+ }
253+ //双手旋转时根据映射出的四个点坐标来判断最小值的临界点
254+ float centerX = (currentSticker .getDst ()[0 ] + currentSticker .getDst ()[4 ]) / 2 ;
255+ float centerY = (currentSticker .getDst ()[1 ] + currentSticker .getDst ()[5 ]) / 2 ;
256+ float rightBottomX = currentSticker .getDst ()[4 ];
257+ float rightBottomY = currentSticker .getDst ()[5 ];
258+
259+ float pathMeasureLength = getPathMeasureLength (centerX , centerY , rightBottomX , rightBottomY );
260+ float newDistance = StickerUtil .calculateDistance (event );
261+ float newRotation = StickerUtil .calculateRotation (event );
262+ if (oldDistance != 0 ) {
263+ Matrix matrix = currentSticker .getMatrix ();
264+ //可以放大 不能缩小
265+ if ((newDistance - oldDistance ) > 0 ) {
266+ matrix .postScale (newDistance / oldDistance , newDistance / oldDistance , midPoint .x ,
267+ midPoint .y );
268+ } else if (pathMeasureLength > currentSticker .getMinStickerSize ()) {
269+ matrix .postScale (newDistance / oldDistance , newDistance / oldDistance , midPoint .x ,
270+ midPoint .y );
271+ }
272+ matrix .postRotate (newRotation - oldRotation , midPoint .x , midPoint .y );
273+ currentSticker .converse ();
274+ }
275+ oldDistance = newDistance ;
276+ oldRotation = newRotation ;
277+ }
278+
230279 private void rotateAndScale (float evX , float evY ) {
231280 float [] src = currentSticker .getRotateSrcPts ();
232281 float [] dst = new float [4 ];
233282 float centerX = (currentSticker .getDst ()[0 ] + currentSticker .getDst ()[4 ]) / 2 ;
234283 float centerY = (currentSticker .getDst ()[1 ] + currentSticker .getDst ()[5 ]) / 2 ;
235284
236285 //获取到触摸点到中心点距离 计算到中心点的距离比例得到X和Y的比例 通过相似三角形计算出最终结果
237- Path path = new Path ();
238- path .moveTo (centerX , centerY );
239- path .lineTo (evX , evY );
240- PathMeasure pathMeasure = new PathMeasure (path , false );
241- if (pathMeasure .getLength () < currentSticker .getMinStickerSize ()) {
242- evX = currentSticker .getMinStickerSize () * (evX - centerX ) / pathMeasure .getLength () + centerX ;
243- evY = currentSticker .getMinStickerSize () * (evY - centerY ) / pathMeasure .getLength () + centerY ;
286+ float pathMeasureLength = getPathMeasureLength (centerX , centerY , evX , evY );
287+ if (pathMeasureLength < currentSticker .getMinStickerSize ()) {
288+ evX = currentSticker .getMinStickerSize () * (evX - centerX ) / pathMeasureLength + centerX ;
289+ evY = currentSticker .getMinStickerSize () * (evY - centerY ) / pathMeasureLength + centerY ;
244290 }
245-
246291 dst [0 ] = centerX ;
247292 dst [1 ] = centerY ;
248293 dst [2 ] = evX ;
249294 dst [3 ] = evY ;
250-
251295 Matrix matrix = currentSticker .getMatrix ();
252296 matrix .reset ();
253297 //并不是将图片从一组点变成另一组点 而是获取这两个组的点变换的matrix
254298 matrix .setPolyToPoly (src , 0 , dst , 0 , 2 );
255299 currentSticker .converse ();
256300 }
257301
302+ private float getPathMeasureLength (float moveX , float moveY , float lineX , float lineY ) {
303+ Path path = new Path ();
304+ path .moveTo (moveX , moveY );
305+ path .lineTo (lineX , lineY );
306+ PathMeasure pathMeasure = new PathMeasure (path , false );
307+ return pathMeasure .getLength ();
308+ }
309+
310+ private float oldDistance = 0f ;
311+ private float oldRotation = 0f ;
312+ private PointF midPoint = new PointF ();
313+
314+
315+ protected PointF calculateMidPoint (@ Nullable MotionEvent event ) {
316+ if (event == null || event .getPointerCount () < 2 ) {
317+ midPoint .set (0 , 0 );
318+ return midPoint ;
319+ }
320+ try {
321+ float x = (event .getX (0 ) + event .getX (1 )) / 2 ;
322+ float y = (event .getY (0 ) + event .getY (1 )) / 2 ;
323+ midPoint .set (x , y );
324+ } catch (IllegalArgumentException e ) {
325+ e .printStackTrace ();
326+ }
327+
328+ return midPoint ;
329+ }
330+
331+
258332 private boolean touchInsideRotateButton (float evX , float evY ) {
259333 return currentSticker != null && new RectF (currentSticker .getDst ()[4 ] - btnRotateBitmap .getWidth () / 2 , currentSticker .getDst ()[5 ] - btnRotateBitmap .getHeight () / 2 , currentSticker .getDst ()[4 ] + btnRotateBitmap .getWidth () / 2 , currentSticker .getDst ()[5 ] + btnRotateBitmap .getHeight () / 2 ).contains (evX , evY );
260334 }
@@ -278,14 +352,16 @@ private boolean touchInsideSticker(float evX, float evY) {
278352 region .setPath (sticker .getBoundPath (), new Region (0 , 0 , getMeasuredWidth (), getMeasuredHeight ()));
279353 if (region .contains ((int ) evX , (int ) evY )) {
280354 currentSticker = sticker ;
355+ int index = mStickers .indexOf (currentSticker );
356+ Collections .swap (mStickers , index , mStickers .size () - 1 );
281357 return true ;
282358 }
283359 }
284360 return false ;
285361 }
286362
287363 private enum TouchState {
288- TOUCHING_INSIDE , TOUCHING_OUTSIDE , PRESS_DELETE , PRESS_SCALE_AND_ROTATE ;
364+ TOUCHING_INSIDE , TOUCHING_OUTSIDE , PRESS_DELETE , PRESS_SCALE_AND_ROTATE , DOUBLE_TOUCH ;
289365 }
290366
291367 public int getMaxStickerCount () {
@@ -365,7 +441,7 @@ public int dip2px(Context c, float dpValue) {
365441 return (int ) (dpValue * scale + 0.5f );
366442 }
367443
368- public Bitmap getFinalStickerView () {
444+ public Bitmap saveSticker () {
369445 currentSticker = null ;
370446 Bitmap bitmap = Bitmap .createBitmap (getWidth (), getHeight (),
371447 Bitmap .Config .ARGB_8888 );
0 commit comments