为什么对layer 的mask感兴趣呢?这是因为前些天看别人写了个刮刮乐的demo,就是根据mask属性来设计,因此对该属性想好好研究下。
概述
layer的alpha通道决定了layer 的content和background的显示量。完全或者部分opaque的像素允许底层内容显示,但是完全opaque的像素组织layer的content和background显示。mask属性默认是nil。配置mask时候,我们需要设置mask的大小和位置,以确保layer和mask 对齐。
通过上段概述(对苹果官方文档的翻译),我们知道,layer内容的显示只是通过mask(layer)的alpha来控制。 要是alpha透明,那么layer也就是透明的啦。
如何获取alpha 的透明度
我们知道layer其实就是承载bitmap的容器。我们可以获取到layer的image。然后将该image转换成只有带有alpha通道的bitmap即可。
UIGraphicsBeginImageContextWithOptions(self.bounds.size, false, 3);
CGContextRef context = UIGraphicsGetCurrentContext();
[layerMask renderInContext:context];
UIImage * imageNew = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
CGSize size = image.size;
int bitmapByteCount =size.width * size.height;
UInt8 * dataN = malloc(bitmapByteCount*sizeof(UInt8));
context = CGBitmapContextCreate(dataN, size.width, size.height, 8, size.width, CGColorSpaceCreateDeviceGray(), kCGImageAlphaOnly);
CGContextClearRect(context, CGRectMake(0, 0, size.width, size.height));
CGContextDrawImage(context, CGRectMake(0, 0, size.width, size.height), image.CGImage);
int width = size.width;
int heigt = size.height;
for (int x = 0; x<width; x++) {
for (int y=0; y<heigt; y++) {
float alpha =dataN[width*x+y];
NSLog(@ "第%d row %d height %f",x,y,alpha);
}
}
这里没有直接对image进行分析,而是将其重新绘制成image,在对image进行分析。原因是直接分析layer的image,改image可能进行压缩,延展了。不好分析。
其实我们刚创建的layer,在第一次渲染的的时候,系统是会给我们创建一个bitmap图。这个图的content是完全透明的。因此我们要是用一个不添加新的contens的新建layer当做mask,那么,layer将是完全透明的。不会显示任何元素。
简单demo
- (instancetype)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
UIImage * image =[UIImage imageNamed:@"123"];
CALayer * layerMask = [CALayer layer];
layerMask.bounds =self.bounds;
layerMask.position= self.center;
layerMask.contents =(__bridge id _Nullable)(image.CGImage);
CALayer * layer = [CALayer layer];
layer.bounds = self.bounds;
layer.position= self.center;
layer.backgroundColor =[UIColor redColor].CGColor;
layer.mask = layerMask;
[self.layer addSublayer:layer];
}
return self;
}

显示结果

具体分析
我们知道mask是一个layer ,那么就有positon 和size,我们看看要是改变positon和size ,会有啥效果。
- (instancetype)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
UIImage * image =[UIImage imageNamed:@"123"];
CALayer * layerMask = [CALayer layer];
layerMask.bounds =CGRectMake(0, 0, 100, 100);
layerMask.position= self.center;
layerMask.contents =(__bridge id _Nullable)(image.CGImage);
CALayer * layer = [CALayer layer];
layer.bounds = self.bounds;
layer.position= self.center;
layer.backgroundColor =[UIColor redColor].CGColor;
layer.mask = layerMask;
[self.layer addSublayer:layer];
}
return self;
}

mask的大小要是比layer小,那么超出mask区域的layer部分不显示。相当于切掉了

对mask进行下列更改
- (instancetype)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
UIImage * image =[UIImage imageNamed:@"123"];
CALayer * layerMask = [CALayer layer];
layerMask.bounds =CGRectMake(0, 0, 100, 100);
layerMask.position= self.center;
layerMask.contents =(__bridge id _Nullable)(image.CGImage);
layerMask.cornerRadius = 50;
layerMask.masksToBounds = YES;
CALayer * layer = [CALayer layer];
layer.bounds = self.bounds;
layer.position= self.center;
layer.backgroundColor =[UIColor redColor].CGColor;
layer.mask = layerMask;
[self.layer addSublayer:layer];
}
return self;
}

我们知道mask的作用主要是控制layer的显示区域,那么,我们利用此特性可以对layer进行区域显示的动画操作
#import "LayerMask.h"
@interface LayerMask()
@property (nonatomic, strong) CADisplayLink *link;
@property (nonatomic, strong) CAShapeLayer *circleMask;
@end
@implementation LayerMask
- (instancetype)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
self.backgroundColor = [UIColor redColor];
//创建一个CAShapeLayer作为MaskLayer
self.circleMask = [CAShapeLayer layer];
self.circleMask.position = self.center;
self.circleMask.bounds = self.bounds;
//设置路径
self.circleMask.path = [UIBezierPath bezierPathWithArcCenter:self.center radius:20 startAngle:0 endAngle:2 * M_PI clockwise:YES].CGPath;
self.circleMask.lineWidth = 5;
self.circleMask.fillRule = kCAFillRuleEvenOdd;
self.layer.mask = self.circleMask;
//添加计时器
self.link = [CADisplayLink displayLinkWithTarget:self selector:@selector(action)];
[self.link addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes];
}
return self;
}
static int num = 1;
-(void)action{
num ++;
self.circleMask.path = [UIBezierPath bezierPathWithArcCenter:self.center radius:20 + num
startAngle:0
endAngle:2 * M_PI clockwise:YES].CGPath;
if (num > 1000) {
[self.link invalidate];
}
}

通过上面的知识,其实我们就可以实现了简单的刮刮乐了。
UIImageView * imageView = [[UIImageView alloc]initWithFrame: [UIScreen mainScreen].bounds];
imageView.image = [UIImage imageNamed:@"guaguale.jpg"];
[self.view addSubview:imageView];
GGView * VC =[[GGView alloc]initWithFrame:CGRectMake(30, 340, 360, 380)];
VC.backgroundColor = UIColor.grayColor;
[self.view addSubview:VC];
@interface GGView()
@property (nonatomic,strong) UIBezierPath * panPath;
@property (nonatomic,strong) CAShapeLayer *layerMask;
@end
@implementation GGView
- (instancetype)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
CAShapeLayer * layer = [CAShapeLayer layer];
self.layerMask= layer;
self.layer.mask = layer;
self.panPath = [UIBezierPath bezierPath];
layer.strokeColor = UIColor.yellowColor.CGColor;
layer.lineCap = kCALineCapRound;
layer.lineWidth = 20;
UIPanGestureRecognizer * panGet = [[UIPanGestureRecognizer alloc]initWithTarget:self action:@selector(pan:)];
[self addGestureRecognizer:panGet];
}
return self;
}
-(void)pan:(UIPanGestureRecognizer *)pan{
CGPoint point = [pan locationInView:self];
if (pan.state ==UIGestureRecognizerStateBegan) {
[self.panPath moveToPoint:point];
}
if (pan.state == UIGestureRecognizerStateChanged) {
[self.panPath addLineToPoint:point];
[self.panPath moveToPoint:point];
self.layerMask.path = self.panPath.CGPath;
[self caclue];
}
}
-(void)drawRect:(CGRect)rect{
}
-(void)caclue{
UIGraphicsBeginImageContextWithOptions(self.bounds.size, false, 3);
CGContextRef context = UIGraphicsGetCurrentContext();
[self.layer renderInContext:context];
UIImage * image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
CGSize size = image.size;
// NSLog(@"%@",NSStringFromCGSize(size));
int bitmapByteCount =size.width * size.height;
UInt8 * data = malloc(bitmapByteCount*sizeof(UInt8));
context = CGBitmapContextCreate(data, size.width, size.height, 8, size.width, CGColorSpaceCreateDeviceGray(), kCGImageAlphaOnly);
CGContextClearRect(context, CGRectMake(0, 0, size.width, size.height));
CGContextDrawImage(context, CGRectMake(0, 0, size.width, size.height), image.CGImage);
int width = size.width;
int mm =0;
for (int x = 0; x<size.width; x++) {
for (int y=0; y<size.height; y++) {
if (data[y*width+x]==0) {
mm++;
}
}
}
float ss = mm*1.0/bitmapByteCount;
if (ss<0.5) {
self.layer.mask = nil;
}
}
@end

网友评论