Android 如何使自定义笔刷的背景透明?
我想用我的自定义画笔在画布上绘制下面的代码,但正如你在图片中看到的,我的画笔的背景是黑色的,尽管没有颜色 虽然我将画笔颜色指定为color.TRANSPARENT或color.parseColor(#00000000),但画笔背景仍然变为黑色 如何使画笔的背景色透明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;
导入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));