2013-03-19 16 views
5

Mój kod jest w zasadzie z tego przykładu (http://corner.squareup.com/2010/07/smooth-signatures.html) i Google API (FingerPaint), ale teraz chcę użyć klasy VelocityTracker w celu zmiany szerokości obrysu w zależności od prędkości mojego palec.Jak narysować ścieżkę o zmiennej szerokości skoku

Pomyślałem, że mogę podzielić ścieżkę na mniejsze części, ale nie znalazłem żadnych przykładów. Jest też ten drugi wpis (http://corner.squareup.com/2012/07/smoother-signatures.html), ale nie mam żadnej konkretnej klasy krzywej Beziera ani nie zbieram wszystkich punktów w ArrayList, więc ich przykład regulacji szerokości skoku nie jest bardzo pomocny.

Czy ktoś ma pomysł, jak sobie z tym poradzić? Zacząłem uczyć się kodu dwa tygodnie temu, więc jestem całkiem nowy w tym wszystkim.

Edytuj: Próbowałem zaimplementować prędkość moich MotionEvents i użyłem LogCat do śledzenia aktualnej prędkości podczas uruchamiania aplikacji. To się udało, ale kiedy próbowałem użyć prędkości jako części parametru dla mPaint.setStrokeWidth, nie dostałem tego, co faktycznie chciałem. Szerokość ścieżki, którą rysuję na moim płótnie, cały czas się zmieniała od momentu, w którym zacząłem rysować linię, aż przesunąłem palec w górę. Dlatego właśnie chciałbym podzielić ścieżkę na mniejsze części, ponieważ tak jak obecnie, tylko ostatnia śledzona prędkość wpływa na szerokość skoku.

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

Udało się zmienić szerokość obrysu w zależności od prędkości mojego palca. W rzeczywistości mam ten sam problem w moim kodzie, ale nie jestem w stanie go jeszcze rozwiązać. – AndroidDev

Odpowiedz

2

Możesz użyć podzielonego obiektu ścieżki za każdym razem, gdy wartość twojego skoku zmienia się w zależności od prędkości. W Tobie SignatureView klasa dodać

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

i podjąć kolejną ArrayList, aby utrzymać wartość skoku dla każdej ścieżki

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

dodać zmienną lastStroke wraz z lastTouchX i lastTouchY. Polecam Ci wykonanie lastStroke typu int.

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

teraz metoda onTouchEvent powinno być coś takiego

@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; 
} 

a OnDraw metodą byłoby

@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); 
    } 
} 

jest to podstawowa idea. musisz go zmodyfikować, aby działał.

+0

hej dzięki za odpowiedź! Myślę, że teraz jestem na dobrej drodze, ale wciąż jest problem. Przypuszczam, że ma to związek z buforującymi Androidem punktami stycznymi, które są "zbyt szybkie". Próbowałem uzyskać je z pętlą podobną do pętli, które mają rozszerzyć dirtyRect. Ale zawsze mam przerwy między ścieżkami. Chciałem ci awansować, ale mój przedstawiciel jest zbyt niski, przepraszam! – Dave

+0

Miałem ten sam problem. Następnie zmodyfikowałem kod tak, aby nowa ścieżka zawsze zaczynała się od ostatniego punktu poprzedniej ścieżki. Na przykład jeśli (x, y) jest ostatnim punktem jednej ścieżki. Następnie następna ścieżka zostanie przeniesiona do (x, y) jako pierwsza. W kategoriach androida "path.movrTo (x, y)" – th1rdey3

+0

@Dave Czy udało Ci się narysować linię płynnie ... Właściwie stoję w obliczu tego samego problemu, czy możesz spojrzeć na to pytanie, które napisałem w stackoverflow http: // stackoverflow .pl/questions/20560322/how-to-draw-path-with-variable-width-in-canvas – AndroidDev

Powiązane problemy