7

私のコードは基本的にこの例 ( http://corner.squareup.com/2010/07/smooth-signatures.htmlVelocityTracker ) と Google API (FingerPaint) からのものですが、ストローク幅を変更するためにクラスを使用したいと考えています。指の速さについて。

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

これを処理する方法を知っている人はいますか?私は 2 週間前にコードを学び始めたので、このすべてのことについてはまったくの初心者です。

編集: MotionEvents の速度を実装しようとしました。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);
}
}
4

1 に答える 1

2

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

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

別の ArrayList を取得して、各パスのストローク値を保持します

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

lastStrokeとともに変数を追加します。タイプの作りをお勧めします。lastTouchXlastTouchYlastStrokeint

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

これが基本的な考え方です。機能させるには、それを変更する必要があります。

于 2013-03-20T20:06:00.037 に答える