以编程方式创建位图掩码

Sim*_*mon 4 android

我在onDraw()中有这个代码.

radius = drawGmpImage(this.gmpImage, canvas);
canvas.drawCircle(kHorizontalOffset, kScreenVerticalOffset, radius , maskPaint);
Run Code Online (Sandbox Code Playgroud)

drawGmpImage创建一个复杂的图形,这个图形上绘有许多线条.这是一个我无法改变的库函数.线条是多边形,可以延伸到圆的圆周之外.

需要的是"清空"在圆圈外面绘制的所有内容.

这是来自iOS的端口,原始开发人员解决方案是使用一个简单的位图掩码,存储为资源,其透明圆圈与绘制的圆的大小相匹配.简单地在绘制的圆上绘制位图具有所需的效果,但在Android上不是一个选项,因为我需要支持所有可能的分辨率和比率.

因此,canvas.drawCircle()调用是我尝试掩盖圆圈外的所有内容的开始.它工作得很好,因为在我绘制的圆上绘制一个实心圆,这样剩下的唯一东西就是绘制圆周外的多边形线.半径是绘制圆的半径.

如何将其反转,以便留下圆圈的内容?

Sim*_*mon 7

为什么你可以花几个小时做某事,放弃,提出问题,然后在20分钟后偶然发现答案?生命的乐趣.

Path path = new Path();
path.addCircle(kHorizontalOffset, kScreenVerticalOffset, radius, Path.Direction.CW);
canvas.clipPath(path);
Run Code Online (Sandbox Code Playgroud)

我错过了将采用任何路径并将其用作剪辑区域的clipPath方法.将我的掩蔽圆圈添加到路径中正是我需要的.

[编辑]

这很好用,但是有一个问题.如果打开硬件加速,它不起作用.我可以关闭加速,但是在剩下的平局中我失去了很多表现,这很复杂.

这是我最终解决它的方式:

onSizeChanged(),创建一个位图掩码.我使用这个颜料在位图的正确位置绘制一个透明圆圈.关键是要使用PorterDuffXfermode.

 maskPaint = new Paint();
 maskPaint.setColor(Color.TRANSPARENT);
 maskPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
 maskPaint.setStyle(Paint.Style.FILL);
Run Code Online (Sandbox Code Playgroud)

然后创建位图

@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {

    super.onSizeChanged(w, h, oldw, oldh);

    createMask(w,h,this.radius);

}

private void createMask(int w,int h, int radius){

    if (mask!=null){mask.recycle();}

    mask = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
    Canvas maskCanvas = new Canvas(mask);
    maskCanvas.drawCircle(w, h, radius, maskPaint);

}
Run Code Online (Sandbox Code Playgroud)

然后在onDraw()中,我只是在整个视图上绘制蒙版:

@Override
protected void onDraw(Canvas canvas){

    // draw the image();
    setRadius(drawGmpImage(this.gmpImage, canvas));
    canvas.drawCircle(kHorizontalOffset, kScreenVerticalOffset, radius , maskPaint);

    // overlay the mask bitmap
    if (mask != null) {
        canvas.drawBitmap(mask, 0f, 0f, bitmapPaint);
    }
Run Code Online (Sandbox Code Playgroud)

如果半径更改,则重新创建掩码:

 private void setRadius(int radius){

     this.radius = radius;
     createMask(kHorizontalOffset, kScreenVerticalOffset, radius);

 }
Run Code Online (Sandbox Code Playgroud)