开发中遇到了如下布局的实现
这个圆形头像可以使用
https://github.com/hdodenhof/CircleImageView
但是圆形头像底部弓形的view却不太好实现
最开始想使用Drawable底部设置圆角来实现,可是效果却不怎么理想,不能完美的与头像对齐
后来想到可以使用Canvas,画出一个圆形,然后剪裁掉上面一块矩形区域
从网上找到的方法大概都如下代码所示
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后面的父布局都会变成黑色
应该改成下面的方式
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,这样可以解决背景变黑的问题
其实也可以用Canvas直接画出来
在红色区域的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);
}
}
布局中稍作更改