title: How to draw a path with variable stroke width
body: <p>My code is basically from this example (<a href="http://corner.squareup.com/2010/07/smooth-signatures.html" rel="noreferrer">http://corner.squareup.com/2010/07/smooth-signatures.html</a>) and Google APIs (FingerPaint) but now I want to use the class <code>VelocityTracker</code> in order to change the stroke width depending on the speed of my finger. </p>
  
  <p>I thought I could split a path into smaller parts but I didn't find any examples. There's also this second post (<a href="http://corner.squareup.com/2012/07/smoother-signatures.html" rel="noreferrer">http://corner.squareup.com/2012/07/smoother-signatures.html</a>) but I do neither have a specific bezier curve class nor do I collect all the points in an <code>ArrayList</code> so their example for adjusting stroke width is not very helpful.</p>
  
  <p>Does anyone have an idea how to handle this? I started to learn code two weeks ago so I'm pretty new in all this stuff.</p>
  
  <p>Edit: I tried to implement the velocity of my MotionEvents and I used LogCat to track the current velocity while running the app. It did work out but when I tried to use the velocity as part of the parameter for mPaint.setStrokeWidth I did not get what I actually wanted. The width of the path I draw on my canvas was changing all the time from the moment I started drawing a line till I moved my finger up. So that's why I want to split a path into smaller parts because as it is now, only the last tracked velocity affects the strokeWidth.</p>
  
  <pre><code>public class SignatureView extends View {
  
      private static final String TAG = SignatureView.class.getSimpleName();
      private static final float STROKE_WIDTH = 10;
      private static final float HALF_STROKE_WIDTH = STROKE_WIDTH / 2;
      private final double TOUCH_TOLERANCE = 5;
      private int h = getResources().getDisplayMetrics().heightPixels;
      private int w = getResources().getDisplayMetrics().widthPixels;
  
      private Path mPath = new Path();
      private Paint mPaint = new Paint();
      private Paint mBitmapPaint = new Paint(Paint.DITHER_FLAG);
      private Bitmap mBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
      private Canvas mCanvas = new Canvas(mBitmap);
  
      private float mX, mY;
      private float lastTouchX, lastTouchY;
      private final RectF dirtyRect = new RectF();
  
  public SignatureView(Context context, AttributeSet attrs) {
      super(context, attrs);
  
      mPaint.setAntiAlias(true);
      mPaint.setColor(Color.BLACK);
      mPaint.setStyle(Paint.Style.STROKE);
      mPaint.setStrokeJoin(Paint.Join.ROUND);
      mPaint.setStrokeWidth(INITIAL_STROKE_WIDTH);
  
      Log.d(TAG, "TOUCH_TOLERANCE = " +TOUCH_TOLERANCE);
  }
  
  @Override
  protected void onDraw(Canvas canvas) {
      canvas.drawBitmap(mBitmap, 0, 0, mBitmapPaint);            
      canvas.drawPath(mPath, mPaint);
  }
  
  @Override
  public boolean onTouchEvent(MotionEvent event) {
      float eventX = event.getX();
      float eventY = event.getY();
      int historySize = event.getHistorySize();
  
      switch (event.getAction()) {
  
          case MotionEvent.ACTION_DOWN:
  
              resetDirtyRect(eventX, eventY);
              mPath.reset();
              mPath.moveTo(eventX, eventY);
              mX = eventX;
              mY = eventY;
              break;
  
          case MotionEvent.ACTION_MOVE:
  
              float dx = Math.abs(eventX - mX);
              float dy = Math.abs(eventY - mY);
  
              if (dx &gt;= TOUCH_TOLERANCE || dy &gt;= TOUCH_TOLERANCE) {
  
                  mPath.quadTo(mX, mY, (eventX + mX)/2, (eventY + mY)/2);
                  mX = eventX;
                  mY = eventY;
              }
  
              for (int i = 0; i &lt; historySize; i++) {
                  float historicalX = event.getHistoricalX(i);
                  float historicalY = event.getHistoricalY(i);
                  expandDirtyRect(historicalX, historicalY);
              }
              break;
  
          case MotionEvent.ACTION_UP:
  
              for (int i = 0; i &lt; historySize; i++) {
                  float historicalX = event.getHistoricalX(i);
                  float historicalY = event.getHistoricalY(i);
                  expandDirtyRect(historicalX, historicalY);
              }
  
              mPath.lineTo(mX, mY);
              mCanvas.drawPath(mPath, mPaint);
              mPath.reset();
              break;
  
          default:
              Log.d(TAG, "Ignored touch event: " + event.toString());
          return false;
      }
  
      // Include half the stroke width to avoid clipping.
          invalidate(     (int) (dirtyRect.left - HALF_STROKE_WIDTH),
                          (int) (dirtyRect.top - HALF_STROKE_WIDTH),
                          (int) (dirtyRect.right + HALF_STROKE_WIDTH),
                          (int) (dirtyRect.bottom + HALF_STROKE_WIDTH));
  
      lastTouchX = eventX;
      lastTouchY = eventY;
      return true;
  }
  
  private void expandDirtyRect(float historicalX, float historicalY) {
      if (historicalX &lt; dirtyRect.left) {
          dirtyRect.left = historicalX;
      } else if (historicalX &gt; dirtyRect.right) {
          dirtyRect.right = historicalX;
      }
      if (historicalY &lt; dirtyRect.top) {
          dirtyRect.top = historicalY;
      } else if (historicalY &gt; dirtyRect.bottom) {
          dirtyRect.bottom = historicalY;
      }
  }
  
  private void resetDirtyRect(float eventX, float eventY) {
  
      dirtyRect.left = Math.min(lastTouchX, eventX);
      dirtyRect.right = Math.max(lastTouchX, eventX);
      dirtyRect.top = Math.min(lastTouchY, eventY);
      dirtyRect.bottom = Math.max(lastTouchY, eventY);
  }
  }
  </code></pre>