2013-03-19 13 views
5

私のコードは基本的にはこの例(http://corner.squareup.com/2010/07/smooth-signatures.html)とGoogle API(FingerPaint)からのコードですが、現在は私のスピードに応じてストロークの幅を変更するためにクラスVelocityTrackerを使用します指。可変ストローク幅でパスを描く方法

パスを小さな部分に分割できると思っていましたが、例は見つかりませんでした。この2番目のポスト(http://corner.squareup.com/2012/07/smoother-signatures.html)もありますが、特定のベジェ曲線クラスを持たず、ArrayListのすべての点を集めるわけでもありませんので、ストローク幅を調整する例はあまり役に立ちません。

これをどのように処理するか考えている人はいますか?私は2週間前にコードを学び始めたので、私はこのすべてのことでかなり新しいです。

編集:私は自分のMotionEventの速度を実装しようとしましたが、LogCatを使用してアプリケーションの実行中の現在の速度を追跡しました。それはうまく動きましたが、mPaint.setStrokeWidthのパラメータの一部としてベロシティを使用しようとしたとき、私は実際に欲しかったものを得られませんでした。私のキャンバスに描くパスの幅は、私が指を上に動かすまで線を描いた瞬間からずっと変化していました。ですから、私は今のところ、最後に追跡された速度だけが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

指の速度に応じてストロークの幅を変更できますか?実際には私のコードでも同じ問題に直面していますが、まだ解決できません。 – AndroidDev

答えて

2

速度に応じてストローク値が変化するたびに、パスオブジェクトを分割することができます。あなたSignatureViewクラスで

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

を追加し、lastTouchXlastTouchYと一緒に変数lastStrokeを追加し、各パスに対して

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

をストローク値を維持するために、別のArrayListを取ります。 intlastStrokeにすることをお勧めします。

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

今、あなたのonTouchEvent方法は、この

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

のようなものであるべきで、あなたのondraw方法は

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

これが基本的な考え方であるだろう。それを動作させるために変更する必要があります。

+0

お返事ありがとう!私は正しい道のりだと思うが、まだ問題はある。私はそれが "速すぎる" Androidのバッファリングタッチポイントと関係していると思う。私はdirtyRectを拡張するためのループと同様のループでそれらを取得しようとしていました。しかし、私は常にパスの間にギャップがあります。 私はあなたにアップアップしたかったが、私の担当者はあまりにも低く、申し訳ありません! – Dave

+0

私は同じ問題を抱えていました。次に、新しいパスが常に前のパスの最後のポイントから開始するようにコードを修正しました。たとえば、(x、y)が1つのパスの最後のポイントであるとします。次に、次のパスが最初に(x、y)に移動します。 android terms 'path.movrTo(x、y)' – th1rdey3

+0

@Daveあなたの行をスムーズに描画することができましたか?実際に同じ問題に直面しています。私がこの質問を見てくれますか?http:// stackoverflow .com/questions/20560322/draw-path-with-variable-width-in-canvas – AndroidDev

関連する問題