更改SignatureView的背景颜色

时间:2014-11-18 09:11:11

标签: android android-canvas

我在堆栈上找到了这个代码并且运行良好。但是,有一个问题。虽然我可以设置其背景颜色,但只要调用 clearSignature()函数,颜色就会变为黑色。

为什么会这样?

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.os.SystemClock;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;

/**
 * A simple view to capture a path traced onto the screen. Initially intended to
 * be used to captures signatures.
 * 
 * @author Andrew Crichton
 * @version 0.1
 */
public class SignatureView extends View
{
    private Path mPath;
    private Paint mPaint;
    private Paint bgPaint = new Paint(Color.TRANSPARENT);

    private Bitmap mBitmap;
    private Canvas mCanvas;

    private float curX, curY;

    private static final int TOUCH_TOLERANCE = 4;
    private static final int STROKE_WIDTH = 4;

    boolean modified = false;

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

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

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

    private void init()
    {
        setFocusable(true);
        mPath = new Path();
        mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        mPaint.setColor(Color.WHITE);
        mPaint.setStyle(Paint.Style.STROKE);
        mPaint.setStrokeWidth(STROKE_WIDTH);
    }

    public void setSigColor(int color)
    {
        mPaint.setColor(color);
    }

    public void setSigColor(int a, int red, int green, int blue)
    {
        mPaint.setARGB(a, red, green, blue);
    }

    public boolean clearSignature()
    {
        if (mBitmap != null)
            createFakeMotionEvents();
        if (mCanvas != null)
        {
            mCanvas.drawColor(Color.BLACK);
            mCanvas.drawPaint(bgPaint);
            mPath.reset();
            invalidate();
        }
        else
        {
            return false;
        }
        return true;
    }

    public Bitmap getImage()
    {
        return this.mBitmap;
    }

    public void setImage(Bitmap bitmap)
    {
        this.mBitmap = bitmap;
        this.invalidate();
    }

    public boolean hasChanged()
    {
        return modified;
    }

    @Override protected void onSizeChanged(int width, int height, int oldWidth, int oldHeight)
    {
        int bitmapWidth = mBitmap != null ? mBitmap.getWidth() : 0;
        int bitmapHeight = mBitmap != null ? mBitmap.getWidth() : 0;
        if (bitmapWidth >= width && bitmapHeight >= height)
            return;
        if (bitmapWidth < width)
            bitmapWidth = width;
        if (bitmapHeight < height)
            bitmapHeight = height;
        Bitmap newBitmap = Bitmap.createBitmap(bitmapWidth, bitmapHeight, Bitmap.Config.ARGB_8888);
        Canvas newCanvas = new Canvas();
        newCanvas.setBitmap(newBitmap);
        if (mBitmap != null)
            newCanvas.drawBitmap(mBitmap, 0, 0, null);
        mBitmap = newBitmap;
        mCanvas = newCanvas;
    }

    private void createFakeMotionEvents()
    {
        MotionEvent downEvent = MotionEvent.obtain(SystemClock.uptimeMillis(), SystemClock.uptimeMillis() + 100, MotionEvent.ACTION_DOWN,
                1f, 1f, 0);
        MotionEvent upEvent = MotionEvent.obtain(SystemClock.uptimeMillis(), SystemClock.uptimeMillis() + 100, MotionEvent.ACTION_UP, 1f,
                1f, 0);
        onTouchEvent(downEvent);
        onTouchEvent(upEvent);
    }

    @Override protected void onDraw(Canvas canvas)
    {
        modified = true;
        canvas.drawColor(Color.RED);
        canvas.drawBitmap(mBitmap, 0, 0, mPaint);
        canvas.drawPath(mPath, mPaint);
    }

    @Override public boolean onTouchEvent(MotionEvent event)
    {
        float x = event.getX();
        float y = event.getY();

        switch (event.getAction())
        {
            case MotionEvent.ACTION_DOWN:
                touchDown(x, y);
                break;
            case MotionEvent.ACTION_MOVE:
                touchMove(x, y);
                break;
            case MotionEvent.ACTION_UP:
                touchUp();
                break;
        }
        invalidate();
        return true;
    }

    /**
     * ---------------------------------------------------------- Private
     * methods ---------------------------------------------------------
     */

    private void touchDown(float x, float y)
    {
        mPath.reset();
        mPath.moveTo(x, y);
        curX = x;
        curY = y;
    }

    private void touchMove(float x, float y)
    {
        float dx = Math.abs(x - curX);
        float dy = Math.abs(y - curY);
        if (dx >= TOUCH_TOLERANCE || dy >= TOUCH_TOLERANCE)
        {
            mPath.quadTo(curX, curY, (x + curX) / 2, (y + curY) / 2);
            curX = x;
            curY = y;
        }
    }

    private void touchUp()
    {
        mPath.lineTo(curX, curY);
        if (mCanvas == null)
        {
            mCanvas = new Canvas();
            mCanvas.setBitmap(mBitmap);
        }
        mCanvas.drawPath(mPath, mPaint);
        mPath.reset();
    }
}

1 个答案:

答案 0 :(得分:1)

我已经更新了原始的SignatureView代码,现在它支持自定义签名背景颜色。此颜色与视图的背景颜色不同!

setSigBackgroundColor()

我还进行了一些其他的优化,因为这是经过最小程度的测试而自行承担风险!

小优化列表:

  • 更好的位图回收等。
  • 回收MotionEvents
  • 添加了签名背景颜色集方法
  • 优化
  • 更改了setImage方法,虽然使用起来还不是很安全!

新代码:

import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.os.SystemClock;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;

/**
 * A simple view to capture a path traced onto the screen. Initially intended to
 * be used to captures signatures.
 * 
 * @author Andrew Crichton
 * @version 0.1.1
 * 
 * Modified by Rolf Smit
 * -Recycle bitmaps
 * -Recycle MotionEvents
 * -Signature Background color changes
 * -Optimizations
 * -Changed setImage method, although still unsafe to use!
 */
public class SignatureView extends View {

    private Path mPath;
    private Paint mPaint;

    private Bitmap mBitmap;
    private Canvas mCanvas;

    private int sigBackgroundColor = Color.TRANSPARENT;

    private float curX, curY;

    private static final int TOUCH_TOLERANCE = 4;
    private static final int STROKE_WIDTH = 4;

    boolean modified = false;

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

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

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

    private void init() {
        setFocusable(true);
        mPath = new Path();
        mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        mPaint.setColor(Color.WHITE);
        mPaint.setStyle(Paint.Style.STROKE);
        mPaint.setStrokeWidth(STROKE_WIDTH);
    }

    public void setSigColor(int color) {
        mPaint.setColor(color);
    }

    public void setSigColor(int alpha, int red, int green, int blue) {
        mPaint.setARGB(alpha, red, green, blue);
    }

    public void setSigBackgroundColor(int color){
        sigBackgroundColor = color;
    }

    public void setSigBackgroundColor(int alpha, int red, int green, int blue){
        sigBackgroundColor = Color.argb(alpha, red, green, blue);
    }

    public boolean clearSignature() {
        if (mBitmap != null) {
            createFakeMotionEvents();
        }
        if (mCanvas != null) {
            mCanvas.drawColor(sigBackgroundColor);
            mPath.reset();
            invalidate();
        } else {
            return false;
        }
        return true;
    }

    public Bitmap getImage() {
        return Bitmap.createBitmap(mBitmap);
    }

    public void setImage(Bitmap bitmap){
        this.mBitmap = bitmap;
        if(mCanvas != null){
            mCanvas.setBitmap(mBitmap);
        }
    }

    public boolean hasChanged() {
        return modified;
    }

    @Override
    protected void onSizeChanged(int width, int height, int oldWidth, int oldHeight) {
        int bitmapWidth = mBitmap != null ? mBitmap.getWidth() : 0;
        int bitmapHeight = mBitmap != null ? mBitmap.getWidth() : 0;
        if (bitmapWidth >= width && bitmapHeight >= height) {
            return;
        }
        if (bitmapWidth < width) {
            bitmapWidth = width;
        }
        if (bitmapHeight < height) {
            bitmapHeight = height;
        }
        Bitmap newBitmap = Bitmap.createBitmap(bitmapWidth, bitmapHeight, Bitmap.Config.ARGB_8888);
        Canvas newCanvas = new Canvas();
        newCanvas.setBitmap(newBitmap);

        mCanvas = newCanvas;

        if (mBitmap != null) {
            newCanvas.drawBitmap(mBitmap, 0, 0, null);
            mBitmap.recycle();
        } else {
            newCanvas.drawColor(sigBackgroundColor);
        }
        mBitmap = newBitmap;
    }

    private void createFakeMotionEvents() {
        MotionEvent downEvent = MotionEvent.obtain(SystemClock.uptimeMillis(), SystemClock.uptimeMillis() + 100, MotionEvent.ACTION_DOWN, 1f, 1f, 0);
        MotionEvent upEvent = MotionEvent.obtain(SystemClock.uptimeMillis(), SystemClock.uptimeMillis() + 100, MotionEvent.ACTION_UP, 1f, 1f, 0);
        onTouchEvent(downEvent);
        onTouchEvent(upEvent);
        downEvent.recycle();
        upEvent.recycle();
    }

    @Override
    protected void onDraw(Canvas canvas) {
        modified = true;
        canvas.drawBitmap(mBitmap, 0, 0, mPaint);
        canvas.drawPath(mPath, mPaint);
    }

    @SuppressLint("ClickableViewAccessibility")
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        float x = event.getX();
        float y = event.getY();

        switch (event.getAction()) {
        case MotionEvent.ACTION_DOWN:
            touchDown(x, y);
            break;
        case MotionEvent.ACTION_MOVE:
            touchMove(x, y);
            break;
        case MotionEvent.ACTION_UP:
            touchUp();
            break;
        }
        invalidate();
        return true;
    }

    private void touchDown(float x, float y) {
        mPath.reset();
        mPath.moveTo(x, y);
        curX = x;
        curY = y;
    }

    private void touchMove(float x, float y) {
        float dx = Math.abs(x - curX);
        float dy = Math.abs(y - curY);
        if (dx >= TOUCH_TOLERANCE || dy >= TOUCH_TOLERANCE) {
            mPath.quadTo(curX, curY, (x + curX) / 2, (y + curY) / 2);
            curX = x;
            curY = y;
        }
    }

    private void touchUp() {
        mPath.lineTo(curX, curY);
        if (mCanvas == null) {
            mCanvas = new Canvas();
            mCanvas.setBitmap(mBitmap);
        }
        mCanvas.drawPath(mPath, mPaint);
        mPath.reset();
    }
}