Android 将手指绘画应用于我自己的视图

Android 将手指绘画应用于我自己的视图,android,canvas,paint,android-custom-view,Android,Canvas,Paint,Android Custom View,我有一个自定义视图,我想对其应用手指绘制。我如何做到这一点 我自己的视图是210x170像素,我想用手指在其中绘制 我真的很困惑如何做到这一点 请尝试以下代码: public class SignatureView extends View { private final String LOG_TAG = this.getClass().getSimpleName(); private float mSignatureWidth = 20f; //YOU CAN CHANGE

我有一个自定义视图,我想对其应用手指绘制。我如何做到这一点

我自己的视图是210x170像素,我想用手指在其中绘制

我真的很困惑如何做到这一点

请尝试以下代码:

public class SignatureView extends View 
{
    private final String LOG_TAG = this.getClass().getSimpleName();

    private float mSignatureWidth = 20f; //YOU CAN CHANGE SIZE OF LINE
    private int mSignatureColor = Color.rgb(00, 119, 204); // SET RGB COLOR
    private boolean mCapturing = true;
    private Bitmap mSignature = null;
    private static final boolean GESTURE_RENDERING_ANTIALIAS = true;
    private static final boolean DITHER_FLAG = true;

    private Paint mPaint = new Paint();
    private Path mPath = new Path();

    private final Rect mInvalidRect = new Rect();

    private float mX;
    private float mY;

    private float mCurveEndX;
    private float mCurveEndY;

    private int mInvalidateExtraBorder = 10;

    public SignatureView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        init();
    }

    public SignatureView(Context context) {
        super(context);
        init();
    }

    public SignatureView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    private void init() {
        setWillNotDraw(false);

        mPaint.setAntiAlias(GESTURE_RENDERING_ANTIALIAS);
        mPaint.setColor(mSignatureColor);
        mPaint.setStyle(Paint.Style.STROKE);
        mPaint.setStrokeJoin(Paint.Join.ROUND);
        mPaint.setStrokeCap(Paint.Cap.ROUND);
        mPaint.setStrokeWidth(mSignatureWidth);
        mPaint.setDither(DITHER_FLAG);
        mPath.reset();
    }

    @Override
    protected void onDraw(Canvas canvas) {

        if (mSignature != null) {
            canvas.drawBitmap(mSignature, null, new Rect(0, 0, getWidth(),getHeight()), null);
        } else {
            canvas.drawPath(mPath, mPaint);
        }
    }

    @Override
    public boolean dispatchTouchEvent(MotionEvent event) {
        if (mCapturing) {
            processEvent(event);
            Log.d(VIEW_LOG_TAG, "dispatchTouchEvent");
            return true;
        } else {
            return false;
        }
    }

    private boolean processEvent(MotionEvent event) {
        switch (event.getAction()) {
        case MotionEvent.ACTION_DOWN:
            touchDown(event);
            invalidate();
            return true;
        case MotionEvent.ACTION_MOVE:
            Rect rect = touchMove(event);
            if (rect != null) {
                invalidate(rect);
            }
            return true;

        case MotionEvent.ACTION_UP:
            touchUp(event, false);
            invalidate();
            return true;

        case MotionEvent.ACTION_CANCEL:
            touchUp(event, true);
            invalidate();
            return true;
        }
        return false;
    }

    private void touchUp(MotionEvent event, boolean b) {
    // TODO Auto-generated method stub
    }

    private Rect touchMove(MotionEvent event) {
        Rect areaToRefresh = null;
        final float x = event.getX();
        final float y = event.getY();
        final float previousX = mX;
        final float previousY = mY;
        areaToRefresh = mInvalidRect;
        // start with the curve end
        final int border = mInvalidateExtraBorder;
        areaToRefresh.set((int) mCurveEndX - border, (int) mCurveEndY - border,
            (int) mCurveEndX + border, (int) mCurveEndY + border);

        float cX = mCurveEndX = (x + previousX) / 2;
        float cY = mCurveEndY = (y + previousY) / 2;

        mPath.quadTo(previousX, previousY, cX, cY);

        // union with the control point of the new curve
        areaToRefresh.union((int) previousX - border, (int) previousY - border,
            (int) previousX + border, (int) previousY + border);

        // union with the end point of the new curve
        areaToRefresh.union((int) cX - border, (int) cY - border, (int) cX
            + border, (int) cY + border);
        mX = x;
        mY = y;
        return areaToRefresh;
    }

    private void touchDown(MotionEvent event) {
        float x = event.getX();
        float y = event.getY();
        mX = x;
        mY = y;
        mPath.moveTo(x, y);

        final int border = mInvalidateExtraBorder;
        mInvalidRect.set((int) x - border, (int) y - border, (int) x + border,
            (int) y + border);

        mCurveEndX = x;
        mCurveEndY = y;
    }

    /**
     * Erases the signature.
     */
    public void clear() {
        mSignature = null;
        mPath.rewind();
        // Repaints the entire view.
        invalidate();
    }

    public boolean isCapturing() {
        return mCapturing;
    }

    public void setIsCapturing(boolean mCapturing) {
        this.mCapturing = mCapturing;
    }

    public void setSignatureBitmap(Bitmap signature) {
        mSignature = signature;
        invalidate();
    }

    public Bitmap getSignatureBitmap() {
        if (mSignature != null) {
            return mSignature;
        } else if (mPath.isEmpty()) {
            return null;
        } else {
            Bitmap bmp = Bitmap.createBitmap(getWidth(), getHeight(),
                Bitmap.Config.ARGB_8888);
            Canvas c = new Canvas(bmp);
            c.drawPath(mPath, mPaint);
            return bmp;
        }
    }

    public void setSignatureWidth(float width) {
        mSignatureWidth = width;
        mPaint.setStrokeWidth(mSignatureWidth);
        invalidate();
    }

    public float getSignatureWidth() {
        return mPaint.getStrokeWidth();
    }

    public void setSignatureColor(int color) {
        mSignatureColor = color;
    }

    /**
     * @return the byte array representing the signature as a PNG file format
     */
    public byte[] getSignaturePNG() {
        return getSignatureBytes(CompressFormat.PNG, 0);
    }

    /**
     * @param quality
     *            Hint to the compressor, 0-100. 0 meaning compress for small
     *            size, 100 meaning compress for max quality.
     * @return the byte array representing the signature as a JPEG file format
     */
    public byte[] getSignatureJPEG(int quality) {
        return getSignatureBytes(CompressFormat.JPEG, quality);
    }

    private byte[] getSignatureBytes(CompressFormat format, int quality) {
        Log.d(LOG_TAG, "getSignatureBytes() path is empty: " + mPath.isEmpty());
        Bitmap bmp = getSignatureBitmap();
        if (bmp == null) {
            return null;
        } else {
            ByteArrayOutputStream stream = new ByteArrayOutputStream();
            getSignatureBitmap().compress(format, quality, stream);
            return stream.toByteArray();
        }
    }
}
在java代码中也使用此类,如:

SignatureView drawView;

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    // Set full screen view
    getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
        WindowManager.LayoutParams.FLAG_FULLSCREEN);
    requestWindowFeature(Window.FEATURE_NO_TITLE);

    drawView = new SignatureView(this);
    setContentView(drawView);
    drawView.requestFocus();
}
希望这将对您有所帮助。

请尝试以下代码:

public class SignatureView extends View 
{
    private final String LOG_TAG = this.getClass().getSimpleName();

    private float mSignatureWidth = 20f; //YOU CAN CHANGE SIZE OF LINE
    private int mSignatureColor = Color.rgb(00, 119, 204); // SET RGB COLOR
    private boolean mCapturing = true;
    private Bitmap mSignature = null;
    private static final boolean GESTURE_RENDERING_ANTIALIAS = true;
    private static final boolean DITHER_FLAG = true;

    private Paint mPaint = new Paint();
    private Path mPath = new Path();

    private final Rect mInvalidRect = new Rect();

    private float mX;
    private float mY;

    private float mCurveEndX;
    private float mCurveEndY;

    private int mInvalidateExtraBorder = 10;

    public SignatureView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        init();
    }

    public SignatureView(Context context) {
        super(context);
        init();
    }

    public SignatureView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    private void init() {
        setWillNotDraw(false);

        mPaint.setAntiAlias(GESTURE_RENDERING_ANTIALIAS);
        mPaint.setColor(mSignatureColor);
        mPaint.setStyle(Paint.Style.STROKE);
        mPaint.setStrokeJoin(Paint.Join.ROUND);
        mPaint.setStrokeCap(Paint.Cap.ROUND);
        mPaint.setStrokeWidth(mSignatureWidth);
        mPaint.setDither(DITHER_FLAG);
        mPath.reset();
    }

    @Override
    protected void onDraw(Canvas canvas) {

        if (mSignature != null) {
            canvas.drawBitmap(mSignature, null, new Rect(0, 0, getWidth(),getHeight()), null);
        } else {
            canvas.drawPath(mPath, mPaint);
        }
    }

    @Override
    public boolean dispatchTouchEvent(MotionEvent event) {
        if (mCapturing) {
            processEvent(event);
            Log.d(VIEW_LOG_TAG, "dispatchTouchEvent");
            return true;
        } else {
            return false;
        }
    }

    private boolean processEvent(MotionEvent event) {
        switch (event.getAction()) {
        case MotionEvent.ACTION_DOWN:
            touchDown(event);
            invalidate();
            return true;
        case MotionEvent.ACTION_MOVE:
            Rect rect = touchMove(event);
            if (rect != null) {
                invalidate(rect);
            }
            return true;

        case MotionEvent.ACTION_UP:
            touchUp(event, false);
            invalidate();
            return true;

        case MotionEvent.ACTION_CANCEL:
            touchUp(event, true);
            invalidate();
            return true;
        }
        return false;
    }

    private void touchUp(MotionEvent event, boolean b) {
    // TODO Auto-generated method stub
    }

    private Rect touchMove(MotionEvent event) {
        Rect areaToRefresh = null;
        final float x = event.getX();
        final float y = event.getY();
        final float previousX = mX;
        final float previousY = mY;
        areaToRefresh = mInvalidRect;
        // start with the curve end
        final int border = mInvalidateExtraBorder;
        areaToRefresh.set((int) mCurveEndX - border, (int) mCurveEndY - border,
            (int) mCurveEndX + border, (int) mCurveEndY + border);

        float cX = mCurveEndX = (x + previousX) / 2;
        float cY = mCurveEndY = (y + previousY) / 2;

        mPath.quadTo(previousX, previousY, cX, cY);

        // union with the control point of the new curve
        areaToRefresh.union((int) previousX - border, (int) previousY - border,
            (int) previousX + border, (int) previousY + border);

        // union with the end point of the new curve
        areaToRefresh.union((int) cX - border, (int) cY - border, (int) cX
            + border, (int) cY + border);
        mX = x;
        mY = y;
        return areaToRefresh;
    }

    private void touchDown(MotionEvent event) {
        float x = event.getX();
        float y = event.getY();
        mX = x;
        mY = y;
        mPath.moveTo(x, y);

        final int border = mInvalidateExtraBorder;
        mInvalidRect.set((int) x - border, (int) y - border, (int) x + border,
            (int) y + border);

        mCurveEndX = x;
        mCurveEndY = y;
    }

    /**
     * Erases the signature.
     */
    public void clear() {
        mSignature = null;
        mPath.rewind();
        // Repaints the entire view.
        invalidate();
    }

    public boolean isCapturing() {
        return mCapturing;
    }

    public void setIsCapturing(boolean mCapturing) {
        this.mCapturing = mCapturing;
    }

    public void setSignatureBitmap(Bitmap signature) {
        mSignature = signature;
        invalidate();
    }

    public Bitmap getSignatureBitmap() {
        if (mSignature != null) {
            return mSignature;
        } else if (mPath.isEmpty()) {
            return null;
        } else {
            Bitmap bmp = Bitmap.createBitmap(getWidth(), getHeight(),
                Bitmap.Config.ARGB_8888);
            Canvas c = new Canvas(bmp);
            c.drawPath(mPath, mPaint);
            return bmp;
        }
    }

    public void setSignatureWidth(float width) {
        mSignatureWidth = width;
        mPaint.setStrokeWidth(mSignatureWidth);
        invalidate();
    }

    public float getSignatureWidth() {
        return mPaint.getStrokeWidth();
    }

    public void setSignatureColor(int color) {
        mSignatureColor = color;
    }

    /**
     * @return the byte array representing the signature as a PNG file format
     */
    public byte[] getSignaturePNG() {
        return getSignatureBytes(CompressFormat.PNG, 0);
    }

    /**
     * @param quality
     *            Hint to the compressor, 0-100. 0 meaning compress for small
     *            size, 100 meaning compress for max quality.
     * @return the byte array representing the signature as a JPEG file format
     */
    public byte[] getSignatureJPEG(int quality) {
        return getSignatureBytes(CompressFormat.JPEG, quality);
    }

    private byte[] getSignatureBytes(CompressFormat format, int quality) {
        Log.d(LOG_TAG, "getSignatureBytes() path is empty: " + mPath.isEmpty());
        Bitmap bmp = getSignatureBitmap();
        if (bmp == null) {
            return null;
        } else {
            ByteArrayOutputStream stream = new ByteArrayOutputStream();
            getSignatureBitmap().compress(format, quality, stream);
            return stream.toByteArray();
        }
    }
}
在java代码中也使用此类,如:

SignatureView drawView;

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    // Set full screen view
    getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
        WindowManager.LayoutParams.FLAG_FULLSCREEN);
    requestWindowFeature(Window.FEATURE_NO_TITLE);

    drawView = new SignatureView(this);
    setContentView(drawView);
    drawView.requestFocus();
}

希望这能对您有所帮助。

我的代码重点介绍了
onTouch
方法。
视图
状态与缓存的
位图一起保存在别处。触摸事件被写入保存位图的状态对象,位图被更新,然后更新的位图被写入
View.onDraw
。另请注意对
requestDisallowWinterCeptTouchEvent
的调用,否则如果屏幕当前允许滚动,触摸事件仍将尝试滚动屏幕。ImmutablePOint只是一个imutable Point类,因为当允许更改状态的点发生变化时,我在值的伸缩方面遇到了问题

hwr是类的实例,它可以记住点和笔划,可以撤消/重做并维护当前显示的一致位图

public boolean onTouchEvent(MotionEvent event)
{
    if (event.getAction() == MotionEvent.ACTION_DOWN)
    {
        this.getParent().requestDisallowInterceptTouchEvent(true);
        this.hwr.addPoint(new ImmutablePoint((int) event.getX(), (int) event.getY()));
    }
    else if (event.getAction() == MotionEvent.ACTION_MOVE)
    {
        this.hwr.addPoint(new ImmutablePoint((int) event.getX(), (int) event.getY()));
    }
    else if (event.getAction() == MotionEvent.ACTION_UP)
    {
        this.getParent().requestDisallowInterceptTouchEvent(false);
        this.hwr.stopDrawing(new ImmutablePoint((int) event.getX(), (int) event.getY()));
        this.callback.pushStroke(this);
    }
    this.invalidate();
    return true;
}
然后onDraw:

@Override
protected void onDraw(Canvas canvas)
{
    // should already be the same size
    canvas.drawBitmap(hwr.getDisplay(), matrix, paint);
}

我的代码关注的是
onTouch
方法。
视图
状态与缓存的
位图一起保存在别处。触摸事件被写入保存位图的状态对象,位图被更新,然后更新的位图被写入
View.onDraw
。另请注意对
requestDisallowWinterCeptTouchEvent
的调用,否则如果屏幕当前允许滚动,触摸事件仍将尝试滚动屏幕。ImmutablePOint只是一个imutable Point类,因为当允许更改状态的点发生变化时,我在值的伸缩方面遇到了问题

hwr是类的实例,它可以记住点和笔划,可以撤消/重做并维护当前显示的一致位图

public boolean onTouchEvent(MotionEvent event)
{
    if (event.getAction() == MotionEvent.ACTION_DOWN)
    {
        this.getParent().requestDisallowInterceptTouchEvent(true);
        this.hwr.addPoint(new ImmutablePoint((int) event.getX(), (int) event.getY()));
    }
    else if (event.getAction() == MotionEvent.ACTION_MOVE)
    {
        this.hwr.addPoint(new ImmutablePoint((int) event.getX(), (int) event.getY()));
    }
    else if (event.getAction() == MotionEvent.ACTION_UP)
    {
        this.getParent().requestDisallowInterceptTouchEvent(false);
        this.hwr.stopDrawing(new ImmutablePoint((int) event.getX(), (int) event.getY()));
        this.callback.pushStroke(this);
    }
    this.invalidate();
    return true;
}
然后onDraw:

@Override
protected void onDraw(Canvas canvas)
{
    // should already be the same size
    canvas.drawBitmap(hwr.getDisplay(), matrix, paint);
}

@库玛和我已经把手指上的颜料弄出来了。问题是,我必须在特定布局的视图上执行此操作。对于如何实现这一目标,我没有找到解决办法this@kumaand我已经弄到手指油了。问题是,我必须在特定布局的视图上执行此操作。对于如何实现这一目标,我没有找到解决办法