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