- ubuntu12.04环境下使用kvm ioctl接口实现最简单的虚拟机
- Ubuntu 通过无线网络安装Ubuntu Server启动系统后连接无线网络的方法
- 在Ubuntu上搭建网桥的方法
- ubuntu 虚拟机上网方式及相关配置详解
CFSDN坚持开源创造价值,我们致力于搭建一个资源共享平台,让每一个IT人在这里找到属于你的精彩世界.
这篇CFSDN的博客文章Android自定义控件之圆形/圆角的实现代码由作者收集整理,如果你对这篇文章有兴趣,记得点赞哟.
1、问题在哪里?
问题来源于app开发中一个很常见的场景——用户头像要展示成圆的:
2、怎么搞?
机智的我,第一想法就是,切一张中间圆形透明、四周与底色相同、尺寸与头像相同的蒙板图片,盖在头像上不就完事了嘛,哈哈哈! 。
在背景纯色的前提下,这的确能简单解决问题,但是如果背景没有这么简单呢?
在这种不规则背景下,有两个问题:
1)、背景图常常是适应手机宽度缩放,而头像的尺寸又是固定宽高dp的,所以固定的蒙板图片是没法保证在不同机型上都和背景图案吻合的.
2)、在这种非纯色背景下,哪天想调整一下头像位置就得重新换图片蒙板,实在是太难维护了…… 。
所以呢,既然头像图片肯定是方的,那就就让imageview圆起来吧.
3、开始干活 。
基本思路是,自定义一个imageview,通过重写ondraw方法画出一个圆形的图片来:
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
|
public
class
imageviewplus
extends
imageview{
private
paint mpaintbitmap =
new
paint(paint.anti_alias_flag);
private
bitmap mrawbitmap;
private
bitmapshader mshader;
private
matrix mmatrix =
new
matrix();
public
imageviewplus(context context, attributeset attrs) {
super
(context, attrs);
}
@override
protected
void
ondraw(canvas canvas) {
bitmap rawbitmap = getbitmap(getdrawable());
if
(rawbitmap !=
null
){
int
viewwidth = getwidth();
int
viewheight = getheight();
int
viewminsize = math.min(viewwidth, viewheight);
float
dstwidth = viewminsize;
float
dstheight = viewminsize;
if
(mshader ==
null
|| !rawbitmap.equals(mrawbitmap)){
mrawbitmap = rawbitmap;
mshader =
new
bitmapshader(mrawbitmap, tilemode.clamp, tilemode.clamp);
}
if
(mshader !=
null
){
mmatrix.setscale(dstwidth / rawbitmap.getwidth(), dstheight / rawbitmap.getheight());
mshader.setlocalmatrix(mmatrix);
}
mpaintbitmap.setshader(mshader);
float
radius = viewminsize /
2
.0f;
canvas.drawcircle(radius, radius, radius, mpaintbitmap);
}
else
{
super
.ondraw(canvas);
}
}
private
bitmap getbitmap(drawable drawable){
if
(drawable
instanceof
bitmapdrawable){
return
((bitmapdrawable)drawable).getbitmap();
}
else
if
(drawable
instanceof
colordrawable){
rect rect = drawable.getbounds();
int
width = rect.right - rect.left;
int
height = rect.bottom - rect.top;
int
color = ((colordrawable)drawable).getcolor();
bitmap bitmap = bitmap.createbitmap(width, height, bitmap.config.argb_8888);
canvas canvas =
new
canvas(bitmap);
canvas.drawargb(color.alpha(color), color.red(color), color.green(color), color.blue(color));
return
bitmap;
}
else
{
return
null
;
}
}
}
|
分析一下代码:
canvas.drawcircle 决定了画出来的形状是圆形,而圆形的内容则是通过 mpaintbitmap.setshader 搞定的.
其中,bitmapshader需要设置bitmap填充imageview的方式(clamp:拉伸边缘, mirror:镜像, repeat:整图重复).
这里其实设成什么不重要,因为我们实际需要的是将bitmap按比例缩放成跟imageview一样大,而不是预置的三种效果.
所以,别忘了 mmatrix.setscale 和 mshader.setlocalmatrix 一起用,将图片缩放一下.
4、更多玩法 —— 支持边框 。
看下面的效果图,如果想给圆形的头像上加一个边框,该怎么搞呢?
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
|
public
class
imageviewplus
extends
imageview{
private
paint mpaintbitmap =
new
paint(paint.anti_alias_flag);
private
paint mpaintborder =
new
paint(paint.anti_alias_flag);
private
bitmap mrawbitmap;
private
bitmapshader mshader;
private
matrix mmatrix =
new
matrix();
private
float
mborderwidth = dip2px(
15
);
private
int
mbordercolor =
0xff0080ff
;
public
imageviewplus(context context, attributeset attrs) {
super
(context, attrs);
}
@override
protected
void
ondraw(canvas canvas) {
bitmap rawbitmap = getbitmap(getdrawable());
if
(rawbitmap !=
null
){
int
viewwidth = getwidth();
int
viewheight = getheight();
int
viewminsize = math.min(viewwidth, viewheight);
float
dstwidth = viewminsize;
float
dstheight = viewminsize;
if
(mshader ==
null
|| !rawbitmap.equals(mrawbitmap)){
mrawbitmap = rawbitmap;
mshader =
new
bitmapshader(mrawbitmap, tilemode.clamp, tilemode.clamp);
}
if
(mshader !=
null
){
mmatrix.setscale((dstwidth - mborderwidth *
2
) / rawbitmap.getwidth(), (dstheight - mborderwidth *
2
) / rawbitmap.getheight());
mshader.setlocalmatrix(mmatrix);
}
mpaintbitmap.setshader(mshader);
mpaintborder.setstyle(paint.style.stroke);
mpaintborder.setstrokewidth(mborderwidth);
mpaintborder.setcolor(mbordercolor);
float
radius = viewminsize /
2
.0f;
canvas.drawcircle(radius, radius, radius - mborderwidth /
2
.0f, mpaintborder);
canvas.translate(mborderwidth, mborderwidth);
canvas.drawcircle(radius - mborderwidth, radius - mborderwidth, radius - mborderwidth, mpaintbitmap);
}
else
{
super
.ondraw(canvas);
}
}
private
bitmap getbitmap(drawable drawable){
if
(drawable
instanceof
bitmapdrawable){
return
((bitmapdrawable)drawable).getbitmap();
}
else
if
(drawable
instanceof
colordrawable){
rect rect = drawable.getbounds();
int
width = rect.right - rect.left;
int
height = rect.bottom - rect.top;
int
color = ((colordrawable)drawable).getcolor();
bitmap bitmap = bitmap.createbitmap(width, height, bitmap.config.argb_8888);
canvas canvas =
new
canvas(bitmap);
canvas.drawargb(color.alpha(color), color.red(color), color.green(color), color.blue(color));
return
bitmap;
}
else
{
return
null
;
}
}
private
int
dip2px(
int
dipval)
{
float
scale = getresources().getdisplaymetrics().density;
return
(
int
)(dipval * scale +
0
.5f);
}
}
|
看代码中,加边框实际上就是用实心纯色的 paint 画了一个圆边,在此基础上画上原来的头像即可.
需要的注意的地方有三个:
1)、圆框的半径不是 radius ,而应该是 radius - mborderwidth / 2.0f 。想象着拿着笔去画线,线其实是画在右图中白色圈的位置,只不过它很粗.
2)、在imageview大小不变的基础上,头像的实际大小要比没有边框的时候小了,所以 mmatrix.setscale 的时候要把边框的宽度去掉.
3)、画头像bitmap的时候不能直接 canvas.drawcircle(radius, radius, radius - mborderwidth, mpaintbitmap) ,这样你会发现头像的右侧和下方边缘被拉伸了(右图) 。
为什么呢?因为 paint 默认是以左上角为基准开始绘制的,此时头像的实际区域是右图中的红框,而超过红框的部分(圆形的右侧和下方),自然被 tilemode.clamp效果沿边缘拉伸了.
所以,需要通过挪动坐标系的位置和调整圆心,才能把头像画在正确的区域(右图绿框)中.
5、更多玩法 —— 支持xml配置 。
既然有了边框,那如果想配置边框的宽度和颜色该如何是好呢?
基本上两个思路:
1)给imageviewplus加上set接口,设置完成之后通过 invalidate(); 重绘一下即可; 。
2)在xml里就支持配置一些自定义属性,这样用起来会方便很多.
这里重点说一下支持xml配置自定义属性.
自定义控件要支持xml配置自定义属性的话,首先需要在 \res\values 里去定义属性:
1
2
3
4
5
6
7
8
9
10
|
<?xml version=
"1.0"
encoding=
"utf-8"
?>
<resources>
<attr name=
"bordercolor"
format=
"color"
/>
<attr name=
"borderwidth"
format=
"dimension"
/>
<declare-styleable name=
"imageviewplus"
>
<attr name=
"bordercolor"
/>
<attr name=
"borderwidth"
/>
</declare-styleable>
</resources>
|
view attrs_imageviewplus.xml 然后在imageviewplus的构造函数中去读取这些自定义属性:
1
2
3
4
5
6
7
8
9
10
11
|
private
static
final
int
default_border_color = color.transparent;
private
static
final
int
default_border_width =
0
;
public
imageviewplus(context context, attributeset attrs) {
super
(context, attrs);
//取xml文件中设定的参数
typedarray ta = context.obtainstyledattributes(attrs, r.styleable.imageviewplus);
mbordercolor = ta.getcolor(r.styleable.imageviewplus_bordercolor, default_border_color);
mborderwidth = ta.getdimensionpixelsize(r.styleable.imageviewplus_borderwidth, dip2px(default_border_width));
ta.recycle();
}
|
在xml布局中使用自定义属性:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
<relativelayout xmlns:android=
"http://schemas.android.com/apk/res/android"
xmlns:tools=
"http://schemas.android.com/tools"
xmlns:snser=
"http://schemas.android.com/apk/res/cc.snser.imageviewplus"
android:layout_width=
"match_parent"
android:layout_height=
"match_parent"
android:background=
"@drawable/wallpaper"
android:orientation=
"vertical"
tools:context=
"${relativepackage}.${activityclass}"
>
<cc.snser.imageviewplus.imageviewplus
android:id=
"@+id/imgplus"
android:layout_width=
"200dp"
android:layout_height=
"300dp"
android:layout_marginbottom=
"50dp"
android:layout_centerhorizontal=
"true"
android:layout_alignparentbottom=
"true"
android:src=
"@drawable/img_square"
snser:bordercolor=
"#ff0080ff"
snser:borderwidth=
"15dp"
/>
</relativelayout>
|
6、更多玩法 —— 圆角imageview 。
搞定了圆形imageview以及对应的边框,那如何实现下面这种圆角的imageview呢?
。
其实原理上一样,把 canvas.drawcircle 对应改成 canvas.drawroundrect 就ok了,直接贴代码吧:
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
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
|
public
class
imageviewplus
extends
imageview{
/**
* android.widget.imageview
*/
public
static
final
int
type_none =
0
;
/**
* 圆形
*/
public
static
final
int
type_circle =
1
;
/**
* 圆角矩形
*/
public
static
final
int
type_rounded_rect =
2
;
private
static
final
int
default_type = type_none;
private
static
final
int
default_border_color = color.transparent;
private
static
final
int
default_border_width =
0
;
private
static
final
int
default_rect_round_radius =
0
;
private
int
mtype;
private
int
mbordercolor;
private
int
mborderwidth;
private
int
mrectroundradius;
private
paint mpaintbitmap =
new
paint(paint.anti_alias_flag);
private
paint mpaintborder =
new
paint(paint.anti_alias_flag);
private
rectf mrectborder =
new
rectf();
private
rectf mrectbitmap =
new
rectf();
private
bitmap mrawbitmap;
private
bitmapshader mshader;
private
matrix mmatrix =
new
matrix();
public
imageviewplus(context context, attributeset attrs) {
super
(context, attrs);
//取xml文件中设定的参数
typedarray ta = context.obtainstyledattributes(attrs, r.styleable.imageviewplus);
mtype = ta.getint(r.styleable.imageviewplus_type, default_type);
mbordercolor = ta.getcolor(r.styleable.imageviewplus_bordercolor, default_border_color);
mborderwidth = ta.getdimensionpixelsize(r.styleable.imageviewplus_borderwidth, dip2px(default_border_width));
mrectroundradius = ta.getdimensionpixelsize(r.styleable.imageviewplus_rectroundradius, dip2px(default_rect_round_radius));
ta.recycle();
}
@override
protected
void
ondraw(canvas canvas) {
bitmap rawbitmap = getbitmap(getdrawable());
if
(rawbitmap !=
null
&& mtype != type_none){
int
viewwidth = getwidth();
int
viewheight = getheight();
int
viewminsize = math.min(viewwidth, viewheight);
float
dstwidth = mtype == type_circle ? viewminsize : viewwidth;
float
dstheight = mtype == type_circle ? viewminsize : viewheight;
float
halfborderwidth = mborderwidth /
2
.0f;
float
doubleborderwidth = mborderwidth *
2
;
if
(mshader ==
null
|| !rawbitmap.equals(mrawbitmap)){
mrawbitmap = rawbitmap;
mshader =
new
bitmapshader(mrawbitmap, tilemode.clamp, tilemode.clamp);
}
if
(mshader !=
null
){
mmatrix.setscale((dstwidth - doubleborderwidth) / rawbitmap.getwidth(), (dstheight - doubleborderwidth) / rawbitmap.getheight());
mshader.setlocalmatrix(mmatrix);
}
mpaintbitmap.setshader(mshader);
mpaintborder.setstyle(paint.style.stroke);
mpaintborder.setstrokewidth(mborderwidth);
mpaintborder.setcolor(mborderwidth >
0
? mbordercolor : color.transparent);
if
(mtype == type_circle){
float
radius = viewminsize /
2
.0f;
canvas.drawcircle(radius, radius, radius - halfborderwidth, mpaintborder);
canvas.translate(mborderwidth, mborderwidth);
canvas.drawcircle(radius - mborderwidth, radius - mborderwidth, radius - mborderwidth, mpaintbitmap);
}
else
if
(mtype == type_rounded_rect){
mrectborder.set(halfborderwidth, halfborderwidth, dstwidth - halfborderwidth, dstheight - halfborderwidth);
mrectbitmap.set(
0
.0f,
0
.0f, dstwidth - doubleborderwidth, dstheight - doubleborderwidth);
float
borderradius = mrectroundradius - halfborderwidth >
0
.0f ? mrectroundradius - halfborderwidth :
0
.0f;
float
bitmapradius = mrectroundradius - mborderwidth >
0
.0f ? mrectroundradius - mborderwidth :
0
.0f;
canvas.drawroundrect(mrectborder, borderradius, borderradius, mpaintborder);
canvas.translate(mborderwidth, mborderwidth);
canvas.drawroundrect(mrectbitmap, bitmapradius, bitmapradius, mpaintbitmap);
}
}
else
{
super
.ondraw(canvas);
}
}
private
int
dip2px(
int
dipval)
{
float
scale = getresources().getdisplaymetrics().density;
return
(
int
)(dipval * scale +
0
.5f);
}
private
bitmap getbitmap(drawable drawable){
if
(drawable
instanceof
bitmapdrawable){
return
((bitmapdrawable)drawable).getbitmap();
}
else
if
(drawable
instanceof
colordrawable){
rect rect = drawable.getbounds();
int
width = rect.right - rect.left;
int
height = rect.bottom - rect.top;
int
color = ((colordrawable)drawable).getcolor();
bitmap bitmap = bitmap.createbitmap(width, height, bitmap.config.argb_8888);
canvas canvas =
new
canvas(bitmap);
canvas.drawargb(color.alpha(color), color.red(color), color.green(color), color.blue(color));
return
bitmap;
}
else
{
return
null
;
}
}
}
|
view imageviewplus.java 。
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
|
<relativelayout xmlns:android=
"http://schemas.android.com/apk/res/android"
xmlns:tools=
"http://schemas.android.com/tools"
xmlns:snser=
"http://schemas.android.com/apk/res/cc.snser.imageviewplus"
android:layout_width=
"match_parent"
android:layout_height=
"match_parent"
android:background=
"@drawable/wallpaper"
android:orientation=
"vertical"
tools:context=
"${relativepackage}.${activityclass}"
>
<cc.snser.imageviewplus.imageviewplus
android:id=
"@+id/imgplus"
android:layout_width=
"200dp"
android:layout_height=
"300dp"
android:layout_marginbottom=
"50dp"
android:layout_centerhorizontal=
"true"
android:layout_alignparentbottom=
"true"
android:src=
"@drawable/img_rectangle"
snser:type=
"rounded_rect"
snser:bordercolor=
"#ff0080ff"
snser:borderwidth=
"10dp"
snser:rectroundradius=
"30dp"
/>
</relativelayout>
view layout
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
<?xml version=
"1.0"
encoding=
"utf-8"
?>
<resources>
<attr name=
"type"
>
<
enum
name=
"none"
value=
"0"
/>
<
enum
name=
"circle"
value=
"1"
/>
<
enum
name=
"rounded_rect"
value=
"2"
/>
</attr>
<attr name=
"bordercolor"
format=
"color"
/>
<attr name=
"borderwidth"
format=
"dimension"
/>
<attr name=
"rectroundradius"
format=
"dimension"
/>
<declare-styleable name=
"imageviewplus"
>
<attr name=
"type"
/>
<attr name=
"bordercolor"
/>
<attr name=
"borderwidth"
/>
<attr name=
"rectroundradius"
/>
</declare-styleable>
</resources>
view attrs_imageviewplus.xml
|
以上就是本文的全部内容,希望对大家学习android软件编程有所帮助.
最后此篇关于Android自定义控件之圆形/圆角的实现代码的文章就讲到这里了,如果你想了解更多关于Android自定义控件之圆形/圆角的实现代码的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
我有一个包含各种子元素的网格,例如网格、Stackpanel、图像...是否可以以裁剪所有内容的方式将网格的角变圆?此外,根网格的大小可能会有所不同,因此无法进行硬编码。 编辑:经过大量搜索,我发现这
我的应用程序采用非常圆润的字体设计,我希望使用勾选框作为 UI 的一部分。带有完全圆形勾选“框”的设计看起来不太好。我正在寻找圆角的标准勾选框,就像您使用容器一样。关于如何实现这一目标的任何想法。我试
我的应用程序采用非常圆润的字体设计,我希望使用勾选框作为 UI 的一部分。带有完全圆形勾选“框”的设计看起来不太好。我正在寻找圆角的标准勾选框,就像您使用容器一样。关于如何实现这一目标的任何想法。我试
所以我应该显示一个时间表,其中每个项目都有一个带有圆角的背景图像...... 我不知道如何为我的 View (当前是 TextView,但我可以更改它)提供背景(这是必须重复的图案)并为其提供圆角..
我想让 JTextArea 有一个圆角,我做了这段代码: public BPosTxtArea() { super(); setOpaque(false); } @Override p
我有两个项目,我在其中创建了一组扩展 card 类的自定义 cards,然后将它们插入到 StaggeredView 中。 我的问题是,在其中一个项目中,卡片角会自动变圆,而在另一个项目中则不会! 此
我正在寻找一些 c++ 绘图图形库来为动态键盘键创建器创建带有抗锯齿选项的圆角。我已经测试过 OpenCV 和 Magick++ 函数,但结果不是很好。谁能帮我解决这个问题? 这是一个使用 Magic
有没有办法使 QLineEdit 小部件的角变圆?如果没有,是否有类似的小部件我可以这样做? 视觉意义: 已解决:(请参阅下面的更多信息) QLineEdit *lineEdit = ne
我正在尝试创建具有圆角和背景的矩形作为重复位图。我是这样写的,但是在角落里得到了位图。 有人能帮忙吗? 背景.xml 最
我有 UIVIew 的代码: override func drawRect(rect: CGRect) { let toolbarSize = CGFloat(UIDevice.current
我正在开发一个 Windows 窗体应用程序(C#、.NET 4.0、VS 2010),其中我有一个非常标准的 MainForm 和一个 ToolStrip(GripStyle:Hidden,Dock
我设法绘制了一个矩形 :-) 但我不知道如何绘制圆角矩形。 谁能帮我解决以下如何四舍五入矩形的代码? let canvas = UIGraphicsGetCurrentContext() rec =
我有以下 SVG: 我想获得类似 CSS 的 border-top-right-radius 和 border-top-bottom-radius 效果。 如何实现
这个问题在这里已经有了答案: How to make an ImageView with rounded corners? (58 个回答) 关闭去年。 我希望图像具有圆角。我实现了这个 xml 代码
我使用此类别并为我的 UITableView 创建大小相同的图像。有没有办法让图像也有圆角?谢谢! + (UIImage *)scale:(UIImage *)image toSize:(CGSize
我对 iPhone 屏幕设计没有太多经验,但我需要制作一个像这样的表格:(图片),我进行了调查,但没有找到任何东西。该表需要有一个圆角,用户将能够插入数据,在本例中是名字、姓氏等......现在我使用
创建具有自定义背景图像的 NSButton 的最佳方法是什么,它能够具有可变的宽度,而不会使角边框看起来被拉伸(stretch)?我知道有一些方便的方法可以使用 UIButton 执行此操作:http
我知道你可以使用 .cornerRadius()将 swiftUI View 的所有角都圆角,但有没有办法只圆角特定的角,例如顶部? 最佳答案 有两个选项,您可以使用 View与 Path ,或者您可
我想在我的游戏屏幕上添加一些黑色轮廓,使其看起来像圆角。 这是我想要达到的效果: 我认为使用着色器可能很容易创建这种效果,而不是在所有内容之上绘制一个巨大的位图。 有人可以帮助我使用此效果的 GLSL
我的 NSTextField 有圆角和白色背景颜色,但 View 本身似乎是矩形的。这意味着圆角和边界矩形之间的空间显示为透明。我该如何填写该区域才能使其不突出? 图片: 代码: let textFi
我是一名优秀的程序员,十分优秀!