Cómo dibujar un camino con ancho de trazo variable
Mi código es básicamente de este ejemplo (http://corner.squareup.com/2010/07/smooth-signatures.html) y las API de Google (FingerPaint) pero ahora quiero usar la claseVelocityTracker
para cambiar el ancho del trazo dependiendo de la velocidad de mi dedo.
Pensé que podría dividir un camino en partes más pequeñas pero no encontré ningún ejemplo. También está este segundo post (http://corner.squareup.com/2012/07/smoother-signatures.html) pero no tengo una clase de curva bezier específica ni colecciono todos los puntos en unaArrayList
por lo que su ejemplo para ajustar el ancho del trazo no es muy útil.
¿Alguien tiene una idea de cómo manejar esto? Comencé a aprender código hace dos semanas, así que soy bastante nuevo en todo esto.
Edición: traté de implementar la velocidad de mis MotionEvents y utilicé LogCat para rastrear la velocidad actual mientras ejecutaba la aplicación. Funcionó pero cuando intenté usar la velocidad como parte del parámetro para mPaint.setStrokeWidth no obtuve lo que realmente quería. El ancho del camino que dibujé en mi lienzo estaba cambiando todo el tiempo desde el momento en que comencé a dibujar una línea hasta que moví mi dedo hacia arriba. Es por eso que quiero dividir un camino en partes más pequeñas porque como está ahora, solo la última velocidad rastreada afecta el Ancho del trazo.
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 >= TOUCH_TOLERANCE || dy >= TOUCH_TOLERANCE) {
mPath.quadTo(mX, mY, (eventX + mX)/2, (eventY + mY)/2);
mX = eventX;
mY = eventY;
}
for (int i = 0; i < 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 < 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 < dirtyRect.left) {
dirtyRect.left = historicalX;
} else if (historicalX > dirtyRect.right) {
dirtyRect.right = historicalX;
}
if (historicalY < dirtyRect.top) {
dirtyRect.top = historicalY;
} else if (historicalY > 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);
}
}