
本文来自谢荣华的博客
首先看效果图. 尽管功能很简单,但在实施时,谷歌和百度很久没有找到解决方案. 许问了这个问题,但没有一个人回答,非常沮丧,在此处记录以与您分享.

叠加效果
首先按照常规方法制作一个简单的绘图板:

public class SketchpadView extends View {
private Paint mPaint;
private Path mPath;
private float mLastX;
private float mLastY;
private Bitmap mBufferBitmap;
private Canvas mBufferCanvas;
public SketchpadView(Context context) {
this(context, null);
}
public SketchpadView(Context context, @Nullable AttributeSet attrs) {
this(context, attrs, 0);
}
public SketchpadView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
private void init() {
// 抗锯齿、防抖动
mPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.DITHER_FLAG);
// 画笔模式为描边
mPaint.setStyle(Paint.Style.STROKE);
// 拐角为圆角
mPaint.setStrokeJoin(Paint.Join.ROUND);
// 两端为圆角
mPaint.setStrokeCap(Paint.Cap.ROUND);
// 画笔宽度
mPaint.setStrokeWidth(50);
// 画笔颜色
mPaint.setColor(getResources().getColor(R.color.colorAccent));
// 画笔透明度,先设置颜色,再设置透明度0-255
mPaint.setAlpha(80);
// 笔迹路径
mPath = new Path();
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
// 双缓存机制
mBufferBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_4444);
mBufferCanvas = new Canvas(mBufferBitmap);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (mBufferBitmap != null) {
canvas.drawBitmap(mBufferBitmap, 0, 0, null);
}
}
@SuppressLint("ClickableViewAccessibility")
@Override
public boolean onTouchEvent(MotionEvent event) {
float x = event.getX();
float y = event.getY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
mLastX = x;
mLastY = y;
mPath.moveTo(x, y);
break;
case MotionEvent.ACTION_MOVE:
mPath.quadTo(mLastX, mLastY, (x + mLastX) / 2, (y + mLastY) / 2);
mBufferCanvas.drawPath(mPath, mPaint);
mLastX = x;
mLastY = y;
invalidate();
break;
case MotionEvent.ACTION_UP:
mPath.reset();
invalidate();
break;
}
return true;
}
}
注: 初始化画笔时,我们将画笔的透明度设置为80. 必须在颜色之后设置透明度,因为颜色中还有一个透明通道,它将覆盖已设置的透明度.
// 画笔颜色
mPaint.setColor(getResources().getColor(R.color.colorAccent));
// 画笔透明度,先设置颜色,再设置透明度0-255
mPaint.setAlpha(80);
看看效果:


颜色渐变
嗯,为什么每个部分都有颜色渐变?
在这里您需要了解Paint类中一个非常重要的方法setXfermode(Xfermode xfermode). 参数Xfermode具有三个子类: 避免Xfermode,PixelXorXfermode和PorterDuffXfermode. API 16中放弃了前两个类,重点放在PorterDuffXfermode类上,PorterDuffXfermode类主要用于图形合成期间的图像过渡模式计算. 共有18种转换模式. 本文重点介绍其中两个SRC_OVER和SRC.
如果未调用setXfermode方法,则默认情况下Paint使用SRC_OVER模式,即首先绘制第一个笔画,绘制第二个笔画时,第二个笔画与第一个笔画重合的部分将是叠加,颜色就会越来越深.
这解释了为什么在上述效果中会有一段颜色渐变笔迹,因为半透明笔迹是叠加的画图板 透明,所以现在我们将模式更改为SRC,即重叠部分仅显示第二笔画画图板 透明,请参见效果:


没有叠加效果
出现了透明效果,但是存在一个问题,即每个笔迹重叠的部分没有使叠加颜色变暗的效果. 继续往下看.
修改以下代码:
public class SketchpadView extends View {
private Paint mPaint;
private Path mPath;
private float mLastX;
private float mLastY;
private Bitmap mBufferBitmap;
private Canvas mBufferCanvas;
public SketchpadView(Context context) {
this(context, null);
}
public SketchpadView(Context context, @Nullable AttributeSet attrs) {
this(context, attrs, 0);
}
public SketchpadView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
private void init() {
// 抗锯齿、防抖动
mPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.DITHER_FLAG);
// 画笔模式为描边
mPaint.setStyle(Paint.Style.STROKE);
// 拐角为圆角
mPaint.setStrokeJoin(Paint.Join.ROUND);
// 两端为圆角
mPaint.setStrokeCap(Paint.Cap.ROUND);
// 画笔宽度
mPaint.setStrokeWidth(50);
// 画笔颜色
mPaint.setColor(getResources().getColor(R.color.colorAccent));
// 画笔透明度,先设置颜色,再设置透明度0-255
mPaint.setAlpha(80);
// 笔迹路径
mPath = new Path();
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
// 双缓存机制
mBufferBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_4444);
mBufferCanvas = new Canvas(mBufferBitmap);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (mBufferBitmap != null) {
canvas.drawBitmap(mBufferBitmap, 0, 0, null);
}
// 修改1
// ACTION_MOVE时,将笔迹临时绘制在画布上
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:
mLastX = x;
mLastY = y;
mPath.moveTo(x, y);
break;
case MotionEvent.ACTION_MOVE:
mPath.quadTo(mLastX, mLastY, (x + mLastX) / 2, (y + mLastY) / 2);
// 修改2
// 将绘制方法移到ACTION_UP中
mLastX = x;
mLastY = y;
invalidate();
break;
case MotionEvent.ACTION_UP:
// 修改3
// ACTION_UP时,将当前一笔的笔迹,绘制到缓存画布上
mBufferCanvas.drawPath(mPath, mPaint);
mPath.reset();
invalidate();
break;
}
return true;
}
}

在未设置“绘制图像”模式的情况下,修改后的代码默认为叠加状态. 在ACTION_MOVE期间,手写内容不是实时绘制在缓存画布上,而是暂时绘制在实际画布上. 当ACTION_UP时,当前笔画一次将笔迹绘制到缓存画布上,然后再绘制到实际画布上,以便笔画的笔触将产生叠加的笔迹效果,请参见最终效果:

叠加效果
这里介绍了半透明笔刷的手写叠加效果. 如果有错误或遗漏,可以给我留言,谢谢!
该代码已上传到GitHub. 欢迎星与叉!
GitHub地址:
此演示的APK下载地址:
本文来自电脑杂谈,转载请注明本文网址:
https://www.pc-fly.com/a/ruanjian/article-206262-1.html
你先合着找一个
这水军水平太差