• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 package com.davemorrissey.labs.subscaleview.test.extension.views;
2 
3 import android.content.Context;
4 import android.graphics.*;
5 import android.graphics.Paint.Cap;
6 import android.graphics.Paint.Style;
7 import android.support.annotation.NonNull;
8 import android.util.AttributeSet;
9 import android.view.MotionEvent;
10 import android.view.View;
11 import android.view.View.OnTouchListener;
12 import com.davemorrissey.labs.subscaleview.SubsamplingScaleImageView;
13 
14 import java.util.ArrayList;
15 import java.util.List;
16 
17 public class FreehandView extends SubsamplingScaleImageView implements OnTouchListener {
18 
19     private final Paint paint = new Paint();
20     private final Path vPath = new Path();
21     private final PointF vPoint = new PointF();
22     private PointF vPrev = new PointF();
23     private PointF vPrevious;
24     private PointF vStart;
25     private boolean drawing = false;
26 
27     private int strokeWidth;
28 
29     private List<PointF> sPoints;
30 
FreehandView(Context context, AttributeSet attr)31     public FreehandView(Context context, AttributeSet attr) {
32         super(context, attr);
33         initialise();
34     }
35 
FreehandView(Context context)36     public FreehandView(Context context) {
37         this(context, null);
38     }
39 
initialise()40     private void initialise() {
41         setOnTouchListener(this);
42         float density = getResources().getDisplayMetrics().densityDpi;
43         strokeWidth = (int)(density/60f);
44     }
45 
46     @Override
onTouch(View view, MotionEvent motionEvent)47     public boolean onTouch(View view, MotionEvent motionEvent) {
48         return false;
49     }
50 
51     @Override
onTouchEvent(@onNull MotionEvent event)52     public boolean onTouchEvent(@NonNull MotionEvent event) {
53         if (sPoints != null && !drawing) {
54             return super.onTouchEvent(event);
55         }
56         boolean consumed = false;
57         int touchCount = event.getPointerCount();
58         switch (event.getActionMasked()) {
59             case MotionEvent.ACTION_DOWN:
60                 if (event.getActionIndex() == 0) {
61                     vStart = new PointF(event.getX(), event.getY());
62                     vPrevious = new PointF(event.getX(), event.getY());
63                 } else {
64                     vStart = null;
65                     vPrevious = null;
66                 }
67                 break;
68             case MotionEvent.ACTION_MOVE:
69                 PointF sCurrentF = viewToSourceCoord(event.getX(), event.getY());
70                 PointF sCurrent = new PointF(sCurrentF.x, sCurrentF.y);
71                 PointF sStart = vStart == null ? null : new PointF(viewToSourceCoord(vStart).x, viewToSourceCoord(vStart).y);
72 
73                 if (touchCount == 1 && vStart != null) {
74                     float vDX = Math.abs(event.getX() - vPrevious.x);
75                     float vDY = Math.abs(event.getY() - vPrevious.y);
76                     if (vDX >= strokeWidth * 5 || vDY >= strokeWidth * 5) {
77                         if (sPoints == null) {
78                             sPoints = new ArrayList<>();
79                             sPoints.add(sStart);
80                         }
81                         sPoints.add(sCurrent);
82                         vPrevious.x = event.getX();
83                         vPrevious.y = event.getY();
84                         drawing = true;
85                     }
86                     consumed = true;
87                     invalidate();
88                 } else if (touchCount == 1) {
89                     // Consume all one touch drags to prevent odd panning effects handled by the superclass.
90                     consumed = true;
91                 }
92                 break;
93             case MotionEvent.ACTION_UP:
94             case MotionEvent.ACTION_POINTER_UP:
95                 invalidate();
96                 drawing = false;
97                 vPrevious = null;
98                 vStart = null;
99         }
100         // Use parent to handle pinch and two-finger pan.
101         return consumed || super.onTouchEvent(event);
102     }
103 
104     @Override
onDraw(Canvas canvas)105     protected void onDraw(Canvas canvas) {
106         super.onDraw(canvas);
107 
108         // Don't draw anything before image is ready.
109         if (!isReady()) {
110             return;
111         }
112 
113         paint.setAntiAlias(true);
114 
115         if (sPoints != null && sPoints.size() >= 2) {
116             vPath.reset();
117             sourceToViewCoord(sPoints.get(0).x, sPoints.get(0).y, vPrev);
118             vPath.moveTo(vPrev.x, vPrev.y);
119             for (int i = 1; i < sPoints.size(); i++) {
120                 sourceToViewCoord(sPoints.get(i).x, sPoints.get(i).y, vPoint);
121                 vPath.quadTo(vPrev.x, vPrev.y, (vPoint.x + vPrev.x) / 2, (vPoint.y + vPrev.y) / 2);
122                 vPrev = vPoint;
123             }
124             paint.setStyle(Style.STROKE);
125             paint.setStrokeCap(Cap.ROUND);
126             paint.setStrokeWidth(strokeWidth * 2);
127             paint.setColor(Color.BLACK);
128             canvas.drawPath(vPath, paint);
129             paint.setStrokeWidth(strokeWidth);
130             paint.setColor(Color.argb(255, 51, 181, 229));
131             canvas.drawPath(vPath, paint);
132         }
133 
134     }
135 
reset()136     public void reset() {
137         this.sPoints = null;
138         invalidate();
139     }
140 
141 }
142