2013-03-19 11 views
5

Il mio codice è fondamentalmente da questo esempio (http://corner.squareup.com/2010/07/smooth-signatures.html) e API Google (FingerPaint) ma ora voglio usare la classe VelocityTracker per modificare la larghezza del tratto in base alla velocità del mio dito.Come disegnare un tracciato con larghezza del tratto variabile

Ho pensato di dividere un tracciato in parti più piccole ma non ho trovato esempi. C'è anche questo secondo post (http://corner.squareup.com/2012/07/smoother-signatures.html) ma non ho né una specifica classe curva di bezier né raccolgo tutti i punti in un ArrayList quindi il loro esempio per la regolazione della larghezza del tratto non è molto utile.

Qualcuno ha un'idea su come gestirlo? Ho iniziato a imparare il codice due settimane fa, quindi sono abbastanza nuovo in tutto questo.

Modifica: ho cercato di implementare la velocità del mio MotionEvents e ho utilizzato LogCat per tracciare la velocità corrente durante l'esecuzione dell'app. Ha funzionato, ma quando ho provato ad usare la velocità come parte del parametro per mPaint.setStrokeWidth non ho ottenuto ciò che volevo realmente. La larghezza del tracciato che disegnavo sulla mia tela cambiava continuamente dal momento in cui ho iniziato a disegnare una linea fino a quando ho spostato il dito verso l'alto. Ecco perché voglio suddividere un tracciato in parti più piccole perché, come lo è ora, solo l'ultima velocità tracciata influisce su strokeWidth.

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); 
} 
} 
+0

È possibile modificare la larghezza del tratto in base alla velocità del mio dito. In realtà anch'io sto affrontando lo stesso problema nel mio codice ma non sono ancora in grado di risolverlo. – AndroidDev

risposta

2

È possibile utilizzare dividere l'oggetto percorso ogni volta che il valore del tratto cambia a seconda della velocità. In te SignatureView classe aggiungere

private Path mPath = new Path(); 
ArrayList<Path> mPaths = new ArrayList<Path>(); 

e prendere un altro ArrayList per mantenere valore della corsa per ogni percorso

ArrayList<int> strokes = new ArrayList<int>(); 

aggiungere una variabile lastStroke con lastTouchX e lastTouchY. Ti consiglierò di creare lastStroke di tipo int.

private int lastStroke = -1; //give an initial value 

ora il tuo metodo di onTouchEvent dovrebbe essere qualcosa di simile

@Override 
public boolean onTouchEvent(MotionEvent event) { 
    float eventX = event.getX(); 
    float eventY = event.getY(); 
    int historySize = event.getHistorySize(); 
    int eventStroke= //calculate stroke size with velocity and make it between 1-10 or any range you seem fit 

    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) { 
       if(lastStroke != evetnStroke){ 
        mPath = new Path(); 
        mPath.moveTo(mX,mY); 
        mPaths.Add(mPath); 
        mStrokes.Add(eventStroke); 
       } 
       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); 
      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; 
    lastStroke = eventStroke; 
    return true; 
} 

e il metodo OnDraw sarebbe

@Override 
protected void onDraw(Canvas canvas) { 
    for(int i=0; i<mPaths.size();i++){ 
     mPaint.setStrokeWidth(strokes.get(i)); 
     canvas.drawPath(mPaths.get(i), mPaint); 
    } 
} 

questa è l'idea di base. è necessario modificarlo per farlo funzionare.

+0

ehi grazie per la risposta! Penso che ora sia sulla strada giusta ma c'è ancora un problema. Immagino che abbia a che fare con i touchpoint del buffering Android che sono "troppo veloci". Stavo cercando di ottenerli con un ciclo simile ai loop che hanno lo scopo di espandere il dirtyRect. Ma ho sempre degli spazi tra i percorsi. Volevo invitarvi, ma il mio rappresentante è troppo basso, mi dispiace! – Dave

+0

Ho avuto lo stesso problema. Quindi ho modificato il codice in modo che un nuovo percorso inizi sempre all'ultimo punto del percorso precedente. Ad esempio se (x, y) è l'ultimo punto di un percorso. Quindi il prossimo percorso passerà prima a (x, y). Nei termini di Android 'path.movrTo (x, y)' – th1rdey3

+0

@Dave Sei riuscito a tracciare la tua linea senza problemi ... In realtà sto affrontando lo stesso problema, puoi guardare questa domanda che avevo postato in StackOverflow http: // StackOverflow .com/questions/20560322/how-to-draw-path-with-variable-width-in-canvas – AndroidDev

Problemi correlati