Android中Canvas擦出部分区域的实现(不擦出背景)

开发中遇到了如下布局的实现

Android中Canvas擦出部分区域的实现(不擦出背景)_第1张图片

这个圆形头像可以使用

https://github.com/hdodenhof/CircleImageView

但是圆形头像底部弓形的view却不太好实现

最开始想使用Drawable底部设置圆角来实现,可是效果却不怎么理想,不能完美的与头像对齐

Android中Canvas擦出部分区域的实现(不擦出背景)_第2张图片

 

 

后来想到可以使用Canvas,画出一个圆形,然后剪裁掉上面一块矩形区域

Android中Canvas擦出部分区域的实现(不擦出背景)_第3张图片

从网上找到的方法大概都如下代码所示

import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.*;
import android.os.Build;
import android.util.AttributeSet;
import android.view.View;
import androidx.annotation.Nullable;
import androidx.annotation.Px;
import androidx.annotation.RequiresApi;

public class FractionCircleView extends View {
    public FractionCircleView(Context context) {
        super(context);
    }

    public FractionCircleView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
    }

    public FractionCircleView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
    public FractionCircleView(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
    }
   
   @Override
    protected void onDraw(Canvas canvas) {

        //创建画笔
        Paint paint = new Paint();
        paint.setAntiAlias(true);
        paint.setColor(Color.parseColor("#9e00a0e9"));

        float size = Math.min(getMeasuredWidth(),getMeasuredHeight());

        float radius = size/2;
        //绘制圆形drawCircle(float cx, float cy, float radius, @NonNull Paint paint)
        // 参数含义依次是 cx : 中心点在布局中的 x 轴位置, cy :中心点在布局中 y 轴位
        // 置,radius :半径 , paint :画笔                                         
        canvas.drawCircle(getMeasuredWidth()/2,getMeasuredHeight()/2,radius,paint);


        canvas.save();
        //设置裁剪区域,设置完成之后Canvas会在裁剪区域绘制
        canvas.clipRect(0,0,getMeasuredWidth(), (int) (getMeasuredHeight()*0.7));
        //Canvas 擦除颜色
        canvas.drawColor(Color.TRANSPARENT,PorterDuff.Mode.CLEAR);
        canvas.restore();

    }
}

布局中使用




    

        
            

            

        

    

这样做虽然实现了底部弓形的view,但是会导致view的背景整个被擦除,包括view后面的父布局都会变成黑色

Android中Canvas擦出部分区域的实现(不擦出背景)_第4张图片

 

 

应该改成下面的方式

import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.*;
import android.os.Build;
import android.util.AttributeSet;
import android.view.View;
import androidx.annotation.Nullable;
import androidx.annotation.Px;
import androidx.annotation.RequiresApi;

public class FractionCircleView extends View {
    public FractionCircleView(Context context) {
        super(context);
    }

    public FractionCircleView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
    }

    public FractionCircleView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
    public FractionCircleView(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
    }

    @Override
    protected void onDraw(Canvas canvas) {

        //创建画笔
        Paint paint = new Paint();
        paint.setAntiAlias(true);
        paint.setColor(Color.parseColor("#9e00a0e9"));

        int size = Math.min(getMeasuredWidth(),getMeasuredHeight());
        Bitmap bitmap = Bitmap.createBitmap(size,size,Bitmap.Config.ARGB_8888);
        Canvas canvasTemp = new Canvas(bitmap);
        //将原先的Canvas绘制在bitmap上面
        canvas.drawBitmap(bitmap,0,0,null);

        float radius = size/2;
        //绘制圆形drawCircle(float cx, float cy, float radius, @NonNull Paint paint)
        // 参数含义依次是 cx : 中心点在布局中的 x 轴位置, cy :中心点在布局中 y 轴位  
        // 置,radius :半径 , paint :画笔                                  
        canvasTemp.drawCircle(getMeasuredWidth()/2,getMeasuredHeight()/2,radius,paint);


        canvasTemp.save();
        //设置裁剪区域,设置完成之后Canvas会在裁剪区域绘制
        canvasTemp.clipRect(0,0,getMeasuredWidth(), (int) (getMeasuredHeight()*0.7));
        //Canvas 擦除颜色,由于擦除颜色使用的不是view本身的Canvas,
        //所以不会擦除背景和父布局的view
        canvasTemp.drawColor(Color.TRANSPARENT,PorterDuff.Mode.CLEAR);
        canvasTemp.restore();

    }
}

上面的代码将原先的Canvas绘制在Bitmap上,使用新的Canvas也在Bitmap上绘制圆形,这个相当于添加了一个圆形进入画布,然后进行剪裁操作,不会影响原先的Canvas,这样可以解决背景变黑的问题

Android中Canvas擦出部分区域的实现(不擦出背景)_第5张图片

 

 

其实也可以用Canvas直接画出来

Android中Canvas擦出部分区域的实现(不擦出背景)_第6张图片

在红色区域的view从底部向上画出一个圆形,这个圆形只有绿色部分能够显示出来,也就实现了这个效果,代码如下

import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.*;
import android.os.Build;
import android.util.AttributeSet;
import android.view.View;
import androidx.annotation.Nullable;
import androidx.annotation.Px;
import androidx.annotation.RequiresApi;

public class FractionCircleView extends View {
    public FractionCircleView(Context context) {
        super(context);
    }

    public FractionCircleView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
    }

    public FractionCircleView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
    public FractionCircleView(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
    }
    

    @Override
    protected void onDraw(Canvas canvas) {

        //dp转换
        final float scale = getContext().getResources().getDisplayMetrics().density;
        int radius = 50;
        radius = (int) (radius * scale + 0.5f);


        Paint paint = new Paint();
        paint.setAntiAlias(true);
        paint.setColor(Color.parseColor("#9e00a0e9"));

        //绘制圆形drawCircle(float cx, float cy, float radius, @NonNull Paint paint)
        // 参数含义依次是 cx : 中心点在布局中的 x 轴位置, cy :中心点在布局中 y 轴位置,radius :半径 , paint :画笔
        canvas.drawCircle(getMeasuredWidth()/2,-(radius-getMeasuredHeight()),radius,paint);
    }
}

布局中稍作更改




    

        
            

            

        

    

 

 

 

 

 

你可能感兴趣的:(Android)