这是一种实现 uiview 镂空效果的方案,可以快速实现任意形状的镂空、文字的镂空、带镂空的毛玻璃效果等。本质上是 uiview 的 maskview 效果。
前言
首先来复习一下遮罩效果的实现。如果我们有一张图片,又恰好有一个圆,当我们把圆设置为图片的遮罩时,会得到这样的结果。
代码实现看上去像是这样:
|
1
|
view.maskview = maskview;
|
那么问题来了,如果我们希望得到下面的结果,该怎么做呢?这看起来像是图层的相减,即原来的图层减去遮罩的部分。
可惜苹果爸爸不够贴心,没有提供方便的接口调用。让我们来看看可以怎么实现。
一、思路
我们的最终目标是,封装出一个接口,调用方式类似于 maskview 属性,可以很方便地对一个 uiview 做镂空效果。
注:以下用 originview 指代需要上效果的 view ,用 maskview 指代充当遮罩的 view 。
目前看来,可以从两个方向入手:
- 修改遮罩的绘制过程
- 修改 maskview 本身
方式一是指,在设置这个属性的时候,对 originview 的视图进行重新绘制,然后在绘制的时候,减掉 maskview 的区域。
方式二是指,当拿到 maskview 的时候,先对 maskview 本身先进行处理,将遮罩范围取反。然后再做遮罩效果,由于遮罩的区域已经相反,于是得到的结果也是相反的,就达到镂空的目的。
看上去方式二比较靠谱,而且最后是调用 uiview 的 setmaskview: 来实现,还可以保留原来遮罩的一些特性。比如当修改 maskview 的 frame 的时候, originview 的遮罩位置也会相应改变。
二、实现
生成相反的遮罩图可以分为三步。假设一开始拿到的 maskview 是下面这样,让我们来看下,转换过程中遮罩图每一步的变化。
注:为了更直观的效果,图片中透明的部分用灰白相间格子来表示(以下相同)。
1、将 maskview 转化为 uiimage
|
1
2
3
4
5
6
7
|
uigraphicsbeginimagecontextwithoptions(self.bounds.size, no, [uiscreen mainscreen].scale);
cgcontexttranslatectm(uigraphicsgetcurrentcontext(),
view.frame.origin.x,
view.frame.origin.y);
[view.layer renderincontext:uigraphicsgetcurrentcontext()];
uiimage *image = uigraphicsgetimagefromcurrentimagecontext();
uigraphicsendimagecontext();
|
这一步拿到了 maskview 对应的 image 图像。此时遮罩图的大小会被同步为 originview 的大小。
uiimage 转换为只有 alpha 通道的 cgcontextref
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
cgimageref originalmaskimage = [image cgimage];
float width = cgimagegetwidth(originalmaskimage);
float height = cgimagegetheight(originalmaskimage);
int stridelength = round_up(width * 1, 4);
unsigned char * alphadata = calloc(stridelength * height, sizeof(unsigned char));
cgcontextref alphaonlycontext = cgbitmapcontextcreate(alphadata,
width,
height,
8,
stridelength,
null,
kcgimagealphaonly);
cgcontextdrawimage(alphaonlycontext, cgrectmake(0, 0, width, height), originalmaskimage);
|
这时候的 alphaonlycontext 对应的图像是下面这样,只保留了 alpha 通道。
cgcontextref 中的 alpha 值进行遍历转换
|
1
2
3
4
5
6
7
8
9
10
|
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
unsigned char val = alphadata[y*stridelength + x];
val = 255 - val;
alphadata[y*stridelength + x] = val;
}
}
cgimageref alphamaskimage = cgbitmapcontextcreateimage(alphaonlycontext);
uiimage *result = [uiimage imagewithcgimage:alphamaskimage];
|
转换后,获得的 result 图像是:
于是,我们就可以用 result 愉快地进行 mask 了。
三、使用
我们可以将上述的步骤,封装为一个方法,用 category 来实现。
|
1
2
3
4
|
@interface uiview (mfsubtractmask)
- (void)setsubtractmaskview:(uiview *)view;
- (uiview *)subtractmaskview;
@end
|
这样调用起来就十分方便了,一行代码搞定:
|
1
|
view.subtractmaskview = maskview;
|
四、局限性
1. subtractmaskview 不会自动刷新
我们知道,当 uiview 的 maskview 的内容动态修改时,会实时反映到 uiview 中。但在本项目中, subtractmaskview 属性会生成一张全新的图片来作为遮罩图,因为不会根据 subtractmaskview 的内容实时来刷新视图。如果需要更新,必须手动调用 setsubtractmaskview: 方法来重新生成遮罩图。
2. setsubtractmaskview: 不宜被频繁调用
setsubtractmaskview: 本质上是生成一个新的遮罩图的过程,该过程涉及图片像素的遍历转换,较为耗时,不宜频繁调用。
综上所述,这种方案适合只生成一次遮罩图的场景。
五、源码
请到 github 上查看完整代码。
总结
以上所述是小编给大家介绍的ios中一行代码实现 uiview 镂空效果,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对快网idc网站的支持!
相关文章
- ASP.NET自助建站系统的数据库备份与恢复操作指南 2025-06-10
- 个人网站服务器域名解析设置指南:从购买到绑定全流程 2025-06-10
- 个人网站搭建:如何挑选具有弹性扩展能力的服务器? 2025-06-10
- 个人服务器网站搭建:如何选择适合自己的建站程序或框架? 2025-06-10
- 64M VPS建站:能否支持高流量网站运行? 2025-06-10
- 2025-07-10 怎样使用阿里云的安全工具进行服务器漏洞扫描和修复?
- 2025-07-10 怎样使用命令行工具优化Linux云服务器的Ping性能?
- 2025-07-10 怎样使用Xshell连接华为云服务器,实现高效远程管理?
- 2025-07-10 怎样利用云服务器D盘搭建稳定、高效的网站托管环境?
- 2025-07-10 怎样使用阿里云的安全组功能来增强服务器防火墙的安全性?
快网idc优惠网
QQ交流群
-
云服务器上建站:操作系统选型(Linux vs Windows)的影响
2025-06-04 45 -
2025-05-25 69
-
2025-05-25 46
-
2025-05-29 59
-
2025-06-04 86








