Android 如何使自定义笔刷的背景透明?

Android 如何使自定义笔刷的背景透明?,android,colors,bitmap,transparent,imagebrush,Android,Colors,Bitmap,Transparent,Imagebrush,我想用我的自定义画笔在画布上绘制下面的代码,但正如你在图片中看到的,我的画笔的背景是黑色的,尽管没有颜色 虽然我将画笔颜色指定为color.TRANSPARENT或color.parseColor(#00000000),但画笔背景仍然变为黑色 如何使画笔的背景色透明 导入android.annotation.SuppressLint; 导入android.content.Context; 导入android.graphics.Bitmap; 导入android.graphics.Canvas;

我想用我的自定义画笔在画布上绘制下面的代码,但正如你在图片中看到的,我的画笔的背景是黑色的,尽管没有颜色

虽然我将画笔颜色指定为color.TRANSPARENT或color.parseColor(#00000000),但画笔背景仍然变为黑色

如何使画笔的背景色透明

导入android.annotation.SuppressLint;
导入android.content.Context;
导入android.graphics.Bitmap;
导入android.graphics.Canvas;
导入android.graphics.Color;
导入android.graphics.Paint;
导入android.graphics.Path;
导入android.graphics.PathMeasure;
导入android.graphics.PorterDuff;
导入android.graphics.PorterDuffXfermode;
导入androidx.annotation.ColorInt;
导入androidx.annotation.IntRange;
导入androidx.annotation.NonNull;
导入androidx.annotation.VisibleForTesting;
导入android.util.AttributeSet;
导入android.util.Pair;
导入android.view.MotionEvent;
导入android.view.view;
导入java.util.Stack;
公共类BrushDrawingView扩展了视图{
静态最终浮动默认画笔大小=50.0f;
静态最终浮动默认值\u橡皮擦\u大小=50.0f;
静态最终整数默认值_不透明度=255;
private float mBrushSize=默认画笔大小;
private float MBrusherSize=默认橡皮擦大小;
private int-mOpacity=默认不透明度;
私有最终堆栈mDrawnPaths=新堆栈();
私有最终堆栈mredopath=新堆栈();
私有最终油漆mDrawPaint=新油漆();
私人画布;
私有布尔模式;
私有位图;
专用路径mPath;
私人浮动mTouchX,mTouchY;
专用静态最终浮动接触公差=4;
私有BrushViewChangeListener mBrushViewChangeListener;
公共BrushDrawingView(上下文){
这个(上下文,空);
}
public BrushDrawingView(上下文、属性集属性){
这(上下文,属性,0);
}
public BrushDrawingView(上下文、属性集属性、int-defStyle){
超级(上下文、属性、定义样式);
设置画图();
}
专用图纸(){
//警告:此行用于禁用硬件加速,以使橡皮擦功能正常工作
setupPathAndPaint();
设置可见性(View.GONE);
}
私有void setupPathAndPaint(){
mPath=新路径();
mDrawPaint.setAntiAlias(true);
mDrawPaint.setStyle(Paint.Style.STROKE);
mDrawPaint.setStrokeJoin(绘制.连接.圆形);
mDrawPaint.setStrokeCap(油漆盖圆形);
mDrawPaint.设定行程宽度(MBRUSHIZE);
mDrawPaint.setAlpha(mOpacity);
}
私人图纸(图纸){
mbrushdawmode=true;
setupPathAndPaint();
}
无效擦除器(){
mbrushdawmode=true;
mDrawPaint.setStrokeWidth(MBRASERSIZE);
setXfermode(新的PorterDuffXfermode(PorterDuff.Mode.CLEAR));
}
公共绘制模式(布尔绘制模式){
this.mbrushdawmode=brushdawmode;
如果(画笔模式){
此.setVisibility(View.VISIBLE);
刷新图形();
}
}
公共位图getBrushBitmap(){
返回笔刷位图;
}
公共位图(位图笔刷位图){
this.brushBitmap=brushBitmap;
}
公共void setOpacity(@IntRange(from=0,to=255)int opacity){
this.mOpacity=(int)(不透明度*2.55f);
setBrushDrawingMode(真);
}
公共int getOpacity(){
回报能力;
}
布尔getBrushDrawingMode(){
返回模式;
}
公共空间大小(浮动大小){
mBrushSize=5+(int)(大小);
setBrushDrawingMode(真);
}
无效颜色(@ColorInt-color){
mDrawPaint.setColor(颜色);
setBrushDrawingMode(真);
}
void setBrushEraserSize(浮动笔刷Erasersize){
this.mBrushEraserSize=brushEraserSize;
setBrushDrawingMode(真);
}
无效设置橡皮擦颜色(@ColorInt-color){
mDrawPaint.setColor(颜色);
setBrushDrawingMode(真);
}
浮点getEraserSize(){
回归市场化;
}
公共浮点数getBrushSize(){
返回大小;
}
int getBrushColor(){
返回mDrawPaint.getColor();
}
公共无效clearAll(){
mDrawnPaths.clear();
mredopath.clear();
if(mDrawCanvas!=null){
mDrawCanvas.drawColor(0,PorterDuff.Mode.CLEAR);
}
使无效();
}
void setBrushViewChangeListener(BrushViewChangeListener BrushViewChangeListener){
mBrushViewChangeListener=brushViewChangeListener;
}
@凌驾
已更改尺寸的受保护空心(整数w、整数h、整数oldw、整数oldh){
super.onSizeChanged(w,h,oldw,oldh);
位图canvasBitmap=Bitmap.createBitmap(w,h,Bitmap.Config.ARGB_8888);
mDrawCanvas=新画布(画布位图);
}
@凌驾
受保护的void onDraw(画布){
用于(笔刷线条路径:MDRAWNPATH){
drawPath(linePath.getDrawPath(),linePath.getDrawPaint());
}
画布绘制路径(mPath,mDrawPaint);
/////
最终位图scaledBitmap=getScaledBitmap();
final float centerX=缩放位图.getWidth()/2;
final float centerY=scaledB位图.getHeight()/2;
最终路径度量值PathMeasure=新路径度量值(mPath,false);
浮动距离=缩放位图.getWidth()/2;
浮动[]位置=新浮动[2];
浮动[]斜率=新浮动[2];
浮动坡度;
while(距离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.graphics.PathMeasure;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import androidx.annotation.ColorInt;
import androidx.annotation.IntRange;
import androidx.annotation.NonNull;
import androidx.annotation.VisibleForTesting;
import android.util.AttributeSet;
import android.util.Pair;
import android.view.MotionEvent;
import android.view.View;

import java.util.Stack;

public class BrushDrawingView extends View {

    static final float DEFAULT_BRUSH_SIZE = 50.0f;
    static final float DEFAULT_ERASER_SIZE = 50.0f;
    static final int DEFAULT_OPACITY = 255;

    private float mBrushSize = DEFAULT_BRUSH_SIZE;
    private float mBrushEraserSize = DEFAULT_ERASER_SIZE;
    private int mOpacity = DEFAULT_OPACITY;

    private final Stack<BrushLinePath> mDrawnPaths = new Stack<>();
    private final Stack<BrushLinePath> mRedoPaths = new Stack<>();
    private final Paint mDrawPaint = new Paint();

    private Canvas mDrawCanvas;
    private boolean mBrushDrawMode;
    private Bitmap brushBitmap;

    private Path mPath;
    private float mTouchX, mTouchY;
    private static final float TOUCH_TOLERANCE = 4;

    private BrushViewChangeListener mBrushViewChangeListener;

    public BrushDrawingView(Context context) {
        this(context, null);
    }

    public BrushDrawingView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public BrushDrawingView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        setupBrushDrawing();
    }

    private void setupBrushDrawing() {
        //Caution: This line is to disable hardware acceleration to make eraser feature work properly
        setupPathAndPaint();
        setVisibility(View.GONE);
    }

    private void setupPathAndPaint() {
        mPath = new Path();
        mDrawPaint.setAntiAlias(true);
        mDrawPaint.setStyle(Paint.Style.STROKE);
        mDrawPaint.setStrokeJoin(Paint.Join.ROUND);
        mDrawPaint.setStrokeCap(Paint.Cap.ROUND);
        mDrawPaint.setStrokeWidth(mBrushSize);
        mDrawPaint.setAlpha(mOpacity);
    }

    private void refreshBrushDrawing() {
        mBrushDrawMode = true;
        setupPathAndPaint();
    }

    void brushEraser() {
        mBrushDrawMode = true;
        mDrawPaint.setStrokeWidth(mBrushEraserSize);
        mDrawPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
    }

    public void setBrushDrawingMode(boolean brushDrawMode) {
        this.mBrushDrawMode = brushDrawMode;
        if (brushDrawMode) {
            this.setVisibility(View.VISIBLE);
            refreshBrushDrawing();
        }
    }

    public Bitmap getBrushBitmap() {
        return brushBitmap;
    }

    public void setBrushBitmap(Bitmap brushBitmap) {
        this.brushBitmap = brushBitmap;
    }

    public void setOpacity(@IntRange(from = 0, to = 255) int opacity) {
        this.mOpacity = (int) (opacity * 2.55f);
        setBrushDrawingMode(true);
    }

    public int getOpacity() {
        return mOpacity;
    }

    boolean getBrushDrawingMode() {
        return mBrushDrawMode;
    }

    public void setBrushSize(float size) {
        mBrushSize = 5 + (int) (size);
        setBrushDrawingMode(true);
    }

    void setBrushColor(@ColorInt int color) {
        mDrawPaint.setColor(color);
        setBrushDrawingMode(true);
    }

    void setBrushEraserSize(float brushEraserSize) {
        this.mBrushEraserSize = brushEraserSize;
        setBrushDrawingMode(true);
    }

    void setBrushEraserColor(@ColorInt int color) {
        mDrawPaint.setColor(color);
        setBrushDrawingMode(true);
    }

    float getEraserSize() {
        return mBrushEraserSize;
    }

    public float getBrushSize() {
        return mBrushSize;
    }

    int getBrushColor() {
        return mDrawPaint.getColor();
    }

    public void clearAll() {
        mDrawnPaths.clear();
        mRedoPaths.clear();
        if (mDrawCanvas != null) {
            mDrawCanvas.drawColor(0, PorterDuff.Mode.CLEAR);
        }
        invalidate();
    }

    void setBrushViewChangeListener(BrushViewChangeListener brushViewChangeListener) {
        mBrushViewChangeListener = brushViewChangeListener;
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        Bitmap canvasBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
        mDrawCanvas = new Canvas(canvasBitmap);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        for (BrushLinePath linePath : mDrawnPaths) {
            canvas.drawPath(linePath.getDrawPath(), linePath.getDrawPaint());
        }
        canvas.drawPath(mPath, mDrawPaint);
        /////
        final Bitmap scaledBitmap = getScaledBitmap();

        final float centerX = scaledBitmap.getWidth() / 2;
        final float centerY = scaledBitmap.getHeight() / 2;

        final PathMeasure pathMeasure = new PathMeasure(mPath, false);

        float distance = scaledBitmap.getWidth() / 2;

        float[] position = new float[2];
        float[] slope = new float[2];

        float slopeDegree;

        while (distance < pathMeasure.getLength())
        {
            pathMeasure.getPosTan(distance, position, slope);
            slopeDegree = (float)((Math.atan2(slope[1], slope[0]) * 180f) / Math.PI);
            canvas.save();
            canvas.translate(position[0] - centerX, position[1] - centerY);
            canvas.rotate(slopeDegree, centerX, centerY);
            canvas.drawBitmap(scaledBitmap, 0, 0, mDrawPaint);
            canvas.restore();
            distance += scaledBitmap.getWidth() + 10;
        }

    }

    /////

    private Bitmap getScaledBitmap()
    {
        // width / height of the bitmap[
        float width = brushBitmap.getWidth();
        float height = brushBitmap.getHeight();

        // ratio of the bitmap
        float ratio = width / height;

        // set the height of the bitmap to the width of the path (from the paint object).
        float scaledHeight = mDrawPaint.getStrokeWidth();

        // to maintain aspect ratio of the bitmap, use the height * ratio for the width.
        float scaledWidth = scaledHeight * ratio;

        // return the generated bitmap, scaled to the correct size.
        return Bitmap.createScaledBitmap(brushBitmap, (int)scaledWidth, (int)scaledHeight, true);
    }

    /**
     * Handle touch event to draw paint on canvas i.e brush drawing
     *
     * @param event points having touch info
     * @return true if handling touch events
     */
    @SuppressLint("ClickableViewAccessibility")
    @Override
    public boolean onTouchEvent(@NonNull MotionEvent event) {
        if (mBrushDrawMode) {
            float touchX = event.getX();
            float touchY = event.getY();
            switch (event.getAction()) {
                case MotionEvent.ACTION_DOWN:
                    touchStart(touchX, touchY);
                    break;
                case MotionEvent.ACTION_MOVE:
                    touchMove(touchX, touchY);
                    break;
                case MotionEvent.ACTION_UP:
                    touchUp();
                    break;
            }
            invalidate();
            return true;
        } else {
            return false;
        }
    }

    boolean undo() {
        if (!mDrawnPaths.empty()) {
            mRedoPaths.push(mDrawnPaths.pop());
            invalidate();
        }
        if (mBrushViewChangeListener != null) {
            mBrushViewChangeListener.onViewRemoved(this);
        }
        return !mDrawnPaths.empty();
    }

    boolean redo() {
        if (!mRedoPaths.empty()) {
            mDrawnPaths.push(mRedoPaths.pop());
            invalidate();
        }

        if (mBrushViewChangeListener != null) {
            mBrushViewChangeListener.onViewAdd(this);
        }
        return !mRedoPaths.empty();
    }


    private void touchStart(float x, float y) {
        mRedoPaths.clear();
        mPath.reset();
        mPath.moveTo(x, y);
        mTouchX = x;
        mTouchY = y;
        if (mBrushViewChangeListener != null) {
            mBrushViewChangeListener.onStartDrawing();
        }
    }

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

    private void touchUp() {
        mPath.lineTo(mTouchX, mTouchY);
        // Commit the path to our offscreen
        mDrawCanvas.drawPath(mPath, mDrawPaint);
        // kill this so we don't double draw

        mDrawnPaths.push(new BrushLinePath(mPath, mDrawPaint));

        /////

        final Bitmap scaledBitmap = getScaledBitmap();

        final float centerX = scaledBitmap.getWidth() / 2;
        final float centerY = scaledBitmap.getHeight() / 2;

        final PathMeasure pathMeasure = new PathMeasure(mPath, false);

        float distance = scaledBitmap.getWidth() / 2;

        float[] position = new float[2];
        float[] slope = new float[2];

        float slopeDegree;

        while (distance < pathMeasure.getLength())
        {
            pathMeasure.getPosTan(distance, position, slope);
            slopeDegree = (float)((Math.atan2(slope[1], slope[0]) * 180f) / Math.PI);
            mDrawCanvas.save();
            mDrawCanvas.translate(position[0] - centerX, position[1] - centerY);
            mDrawCanvas.rotate(slopeDegree, centerX, centerY);
            mDrawCanvas.drawBitmap(scaledBitmap, 0, 0, mDrawPaint);
            mDrawCanvas.restore();
            distance += scaledBitmap.getWidth() + 10;
        }

        /////

        mPath = new Path();
        if (mBrushViewChangeListener != null) {
            mBrushViewChangeListener.onStopDrawing();
            mBrushViewChangeListener.onViewAdd(this);
        }
    }

    @VisibleForTesting
    Paint getDrawingPaint() {
        return mDrawPaint;
    }

    @VisibleForTesting
    Pair<Stack<BrushLinePath>, Stack<BrushLinePath>> getDrawingPath() {
        return new Pair<>(mDrawnPaths, mRedoPaths);
    }
}

public interface BrushViewChangeListener {
    void onViewAdd(BrushDrawingView brushDrawingView);

    void onViewRemoved(BrushDrawingView brushDrawingView);

    void onStartDrawing();

    void onStopDrawing();
}

class BrushLinePath {
    private final Paint mDrawPaint;
    private final Path mDrawPath;

    BrushLinePath(final Path drawPath, final Paint drawPaints) {
        mDrawPaint = new Paint(drawPaints);
        mDrawPath = new Path(drawPath);
    }

    Paint getDrawPaint() {
        return mDrawPaint;
    }

    Path getDrawPath() {
        return mDrawPath;
    }
}
    mDrawPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_OVER));