内容简介:这是一种实现首先来复习一下遮罩效果的实现。如果我们有一张图片,又恰好有一个圆,当我们把圆设置为图片的遮罩时,会得到这样的结果。代码实现看上去像是这样:
这是一种实现 UIView
镂空效果的方案,可以快速实现任意形状的镂空、文字的镂空、带镂空的毛玻璃效果等。本质上是 UIView
的 maskView
效果的「取反」。
前言
首先来复习一下遮罩效果的实现。如果我们有一张图片,又恰好有一个圆,当我们把圆设置为图片的遮罩时,会得到这样的结果。
代码实现看上去像是这样:
view.maskView = maskView; 复制代码
那么问题来了,如果我们希望得到下面的结果,该怎么做呢?这看起来像是图层的相减,即原来的图层减去遮罩的部分。
可惜苹果爸爸不够贴心,没有提供方便的接口调用。让我们来看看可以怎么实现。
一、思路
我们的最终目标是,封装出一个接口,调用方式类似于 maskView
属性,可以很方便地对一个 UIView
做镂空效果。
**注:**以下用 originView
指代需要上效果的 view
,用 maskView
指代充当遮罩的 view
。
目前看来,可以从两个方向入手:
maskView
方式一是指,在设置这个属性的时候,对 originView
的视图进行重新绘制,然后在绘制的时候,减掉 maskView
的区域。
方式二是指,当拿到 maskView
的时候,先对 maskView
本身先进行处理,将遮罩范围取反。然后再做遮罩效果,由于遮罩的区域已经相反,于是得到的结果也是相反的,就达到镂空的目的。
看上去方式二比较靠谱,而且最后是调用 UIView
的 setMaskView:
来实现,还可以保留原来遮罩的一些特性。比如当修改 maskView
的 frame
的时候, originView
的遮罩位置也会相应改变。
二、实现
生成相反的遮罩图可以分为三步。假设一开始拿到的 maskView
是下面这样,让我们来看下,转换过程中遮罩图每一步的变化。
**注:**为了更直观的效果,图片中透明的部分用灰白相间格子来表示(以下相同)。
1、将 maskView
转化为 UIImage
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
的大小。
2、将 UIImage
转换为只有 alpha
通道的 CGContextRef
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
通道。
3、将 CGContextRef
中的 alpha
值进行遍历转换
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
来实现。
@interface UIView (MFSubtractMask) - (void)setSubtractMaskView:(UIView *)view; - (UIView *)subtractMaskView; @end 复制代码
这样调用起来就十分方便了,一行代码搞定:
view.subtractMaskView = maskView; 复制代码
四、局限性
1. subtractMaskView
不会自动刷新
我们知道,当 UIView
的 maskView
的内容动态修改时,会实时反映到 UIView
中。但在本项目中, subtractMaskView
属性会生成一张全新的图片来作为遮罩图,因为不会根据 subtractMaskView
的内容实时来刷新视图。如果需要更新,必须手动调用 setSubtractMaskView:
方法来重新生成遮罩图。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:- 幻术,一行代码实现镂空效果
- CSS实现镂空效果
- 用纯 CSS 实现镂空效果
- jquery.guide.js新版上线操作向导镂空提示jQuery插件
- jquery.guide.js新版上线操作向导镂空提示jQuery插件
- 一行一行源码分析清楚AbstractQueuedSynchronizer
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。