Core Animation+Quartz2D使用CALayer.mask来裁减图形
我们在做iOS应用时会有这么个需求:想对一个UIView视图做部分裁减,使得被裁减部分显示其子视图部分,即其底图。
我们一般可以通过让美术人员做一个相同尺寸的图,将裁减部分做成透明即可。另一种可以通过程序来做。下面我将介绍如何通过Cocoa Framework中的QuartzCore Framework来实现这个效果。
基本思路是,我们先通过Quartz2D画一个视图,先用alpha为1的像素填充所指定的矩形,然后用alpha为0的像素画一个裁减图形。最后,将绘制好的这个UIView对象的layer作为被裁减的视图的layer的mask。
先看Quartz2D部分,这部分代码定制了一个UIView类:
// // MyQuartzView.m // QuartzTest // // Created by zenny_chen on 12-2-21. // Copyright (c) 2012年 GreenGames Studio. All rights reserved. // #import "MyQuartzView.h" // Quartz2D以及Core Animation所需要的头文件 #import <QuartzCore/QuartzCore.h> #import <CoreText/CoreText.h> @implementation MyQuartzView - (id)initWithFrame:(CGRect)frame { self = [super initWithFrame:frame]; if (self) { // Initialization code } return self; } // Only override drawRect: if you perform custom drawing. // An empty implementation adversely affects performance during animation. - (void)drawRect:(CGRect)rect { // Drawing code // 创建Quartz上下文 CGContextRef context = UIGraphicsGetCurrentContext(); // 先填充一个alpha只为1的白色矩形 CGContextSetRGBFillColor(context, 1.0f, 1.0f, 1.0f, 1.0f); CGContextFillRect(context, CGRectMake(0.0f, 0.0f, self.frame.size.width, self.frame.size.height)); // 对于iOS坐标系,调整一下坐标系的表示,使得原点处于左下侧 // 这样与我们平时在数学中用的坐标系可取得一致 CGContextTranslateCTM(context, 0.0f, self.frame.size.height); CGContextScaleCTM(context, 1.0f, -1.0f); // 创建一个三角Path CGMutablePathRef path = CGPathCreateMutable(); // 调用CGPathMoveToPoint来开启一个子Path CGPathMoveToPoint(path, &CGAffineTransformIdentity, 0.0f, self.frame.size.height); CGPathAddLineToPoint(path, &CGAffineTransformIdentity, 0.0f, 0.0f); CGPathAddLineToPoint(path, &CGAffineTransformIdentity, self.frame.size.width * 0.125f, 0.0f); CGPathAddLineToPoint(path, &CGAffineTransformIdentity, 0.0f, self.frame.size.height); CGPathCloseSubpath(path); // 设置Path的混合模式: // kCGBlendModeDestinationIn表示:如果alpha为0,那么采用目标像素 CGContextSetBlendMode(context, kCGBlendModeDestinationIn); // 这里主要设置该path的alpha值为0 CGContextSetRGBFillColor(context, 0.0f, 0.0f, 0.0f, 0.0f); // 添加Path并绘制该Path CGContextAddPath(context, path); CGContextFillPath(context); CGPathRelease(path); } @end
然后,我们再看看主控制器里面的代码:
// // ViewController.m // QuartzTest // // Created by zenny_chen on 12-2-21. // Copyright (c) 2012年 GreenGames Studio. All rights reserved. // #import "ViewController.h" #import "MyQuartzView.h" #import <QuartzCore/QuartzCore.h> @interface ViewController () @end @implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view, typically from a nib. // 设置主视图的背景色 self.view.backgroundColor = [UIColor colorWithRed:0.2f green:0.2f blue:0.2f alpha:1.0f]; // 创建一个红色背景的矩形图 UIView *aView = [[UIView alloc] initWithFrame:CGRectMake(100.0f, 100.0f, 160.0f, 160.0f)]; aView.backgroundColor = [UIColor redColor]; [self.view addSubview:aView]; [aView release]; // 创建掩模视图,其尺寸与所要裁减的视图的尺寸一样 MyQuartzView *myView = [[MyQuartzView alloc] initWithFrame:CGRectMake(0.0f, 0.0f, 160.0f, 160.0f)]; // 这里要注意的是,必须将掩模视图的背景色的alpha值填充为0 myView.backgroundColor = [UIColor clearColor]; // 将掩模视图的layer作为被裁减视图的layer的mask aView.layer.mask = myView.layer; // 注意,这里的myView不能调release方法, // 因为aView.layer.mask = myView.layer这句并没有将myView给retain住。 } - (void)viewDidUnload { [super viewDidUnload]; // Release any retained subviews of the main view. } - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation { return (interfaceOrientation == UIInterfaceOrientationPortrait); } @end