自定义View之圆角实现

疫情概要

截至2月11日24时,据31个省(自治区、直辖市)和新疆生产建设兵团报告,现有确诊病例38800例(其中重症病例8204例),累计治愈出院病例4740例,累计死亡病例1113例,累计报告确诊病例44653例,现有疑似病例16067例。累计追踪到密切接触者451462人,尚在医学观察的密切接触者185037人。

前言

最近项目中需要使用到圆角来展示内容。原先用得多的是用Canvas.clipXXX()或者是使用Paint.setXfermode(),现在用一个简单的方式就可实现,就是SDK21开始引入的ViewOutlineProvider类,用法也很简单。

ViewOutlineProvider

ViewOutlineProvider

Interface by which a View builds its Outline, used for shadow casting and clipping.

从上面官网的说明可以了解到ViewOutlineProvider有两个作用:裁剪、阴影。

用法

利用裁剪实现圆角方法:

1
2
3
4
5
6
7
8
9
10
ViewOutlineProvider outlineProvider = new ViewOutlineProvider() {
@Override
public void getOutline(View view, Outline outline) {
outline.setRoundRect(0, 0, view.getWidth(), view.getHeight(), 30);
//30为圆角半径,可自行修改
}
};
View view = findViewById(R.id.view);//需要设置圆角的控件
view.setOutlineProvider(outlineProvider);//将ViewOutlineProvider设置给view
view.setClipToOutline(true);//只有设置为true才能进行裁剪,false时不裁剪

可以看到只要3步即可实现:

  1. 创建ViewOutlineProvider,
  2. 实现getOutline()方法,使用Outline.setRoundRect()设置圆角矩阵,即裁剪后留下的有效区域
  3. 将ViewOutlineProvider设置给需要的View,并调用View.setClipToOutline(true)开启裁剪

当然也可以调用View.setClipToOutline(false)关闭裁剪。

还有如下方法提供不同效果:

Outline.setOval()

Outline.setRect()

等……..

Outline类内部主要是有如下几个成员变量记录

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
/** @hide */
@Mode
public int mMode = MODE_EMPTY;

/**
* Only guaranteed to be non-null when mode == MODE_CONVEX_PATH
*
* @hide
*/
public Path mPath;

/** @hide */
public final Rect mRect = new Rect();
/** @hide */
public float mRadius = RADIUS_UNDEFINED;
/** @hide */
public float mAlpha;

利弊

利:使用方便

弊:必须要SDK>=21才能使用

SDK<21解决方式

SDK<21的这里提供一种,可直接使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96

/**
* 圆角的RelativeLayout,如需要其他布局的圆角,可直接修改继承的父类
*/

public class RoundRectLayout extends RelativeLayout {

//圆角裁剪范围
private Path mPath;
//圆角半径
private int mRadius = 30;

private int mWidth;
private int mHeight;

//是否开启圆角
private boolean mRoundMode = true;

public RoundRectLayout(Context context) {
super(context);
init();
}

public RoundRectLayout(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}

@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
mWidth = w;
mHeight = h;
}

private void init() {
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.JELLY_BEAN) {
setBackground(new ColorDrawable(0x33ff0000));
} else {
setBackgroundDrawable(new ColorDrawable(0x33ff0000));
}

mPath = new Path();
mPath.setFillType(Path.FillType.EVEN_ODD);

}

/**
* 设置是否圆角裁边
*
* @param roundMode
*/
public void setRoundMode(boolean roundMode) {
mRoundMode = roundMode;
invalidate();
}

/**
* 设置圆角半径
*
* @param radius
*/
public void setCornerRadius(int radius) {
mRadius = radius;
invalidate();
}

private void refreshRoundPath() {

mPath.reset();

if (mRoundMode) {
mPath.addRoundRect(new RectF(0, 0, mWidth, mHeight), mRadius, mRadius, Path.Direction.CW);
}

}

@Override
public void draw(Canvas canvas) {

if (mRoundMode) {
int saveCount = canvas.save();

refreshRoundPath();

canvas.clipPath(mPath);
super.draw(canvas);

canvas.restoreToCount(saveCount);
} else {
super.draw(canvas);
}


}
}
坚持原创技术分享,您的支持是对我最大的鼓励!