上一篇文章介紹了maskView的原理和基本使用
接下來介紹下maskView的進階使用
一.利用maskView使用多種圖片做漸變切換動畫
1.素材
// 上述素材按照順序分別是‘base’,'background',''mask','mask1';
self.view.backgroundColor = [UIColor whiteColor];
UIImageView *baseGround = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 200, 200)];
baseGround.image = [UIImage imageNamed:@"base"];
baseGround.center = self.view.center;
[self.view addSubview: baseGround];
UIImageView *upGround = [[UIImageView alloc] initWithFrame:baseGround.frame];
upGround.image = [UIImage imageNamed:@"background"];
[self.view addSubview:upGround];
UIView *mask = [[UIView alloc] initWithFrame:upGround.bounds];
upGround.maskView = mask;
UIImageView *picOne = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 100, 400)];
picOne.image = [UIImage imageNamed:@"mask1"];
[mask addSubview:picOne];
UIImageView *picTwo = [[UIImageView alloc] initWithFrame:CGRectMake(100, -200, 100, 400)];
picTwo.image = [UIImage imageNamed:@"mask"];
[mask addSubview:picTwo];
[UIView animateWithDuration:5.f delay:5.f options:0 animations:^{
picOne.y -= 400;
picTwo.y += 400;
} completion:^(BOOL finished) {
}];
- Code原理解析:
mask默認色為透明(clearColor),如果picOne和picTwo不存在時邪锌,由于mask是透明,切mask又是upGround的maskView赴蝇,則upGround也會透明超埋,即效果圖只會看到baseGround谢澈。在此例中一開始mask有picOne和picTwo兩個子View,且picOne和picTwo顯示在mask上的部分不是透明部分,所以一開始效果圖只會看到backGround.
- 圖片漸變動畫實現(xiàn)原理:
隨著picOne和picTwo的上下部分移動,最終的效果是picOne和picTwo顯示在mask上的都是透明部分旧烧,當顯示在mask上的控件透明時,則mask也會透明画髓,那么backGround也會透明掘剪,最終的效果圖就是逐漸看不到backGround,然后顯示baseGround.
運行效果圖
二.maskView配合CAGradientLayer使用
iPhone滑動解鎖效果
先來個Demo來解釋下CAGradientLayer吧奈虾,先了解下CAGradientLayer是個啥玩意杖小,
- (void)viewDidLoad {
[super viewDidLoad];
self.view.backgroundColor = [UIColor grayColor];
// 漸變Layer
CAGradientLayer *gradientLayer = [CAGradientLayer layer];
[self.view.layer addSublayer:gradientLayer];
gradientLayer.frame = CGRectMake(0, 200, self.view.width, 64);
gradientLayer.colors = @[
(__bridge id)[UIColor blackColor].CGColor,
(__bridge id)[UIColor whiteColor].CGColor,
(__bridge id)[UIColor blackColor].CGColor, ];
gradientLayer.locations = @[@0.25,@0.5,@0.75];
}
運行效果圖:
CAGradientLayer可用來處理顏色漸變,它的漸變色也可以做隱式動畫
此例用frame設(shè)置了layer的位置愚墓,也可以用position屬性設(shè)置layer的位置
colors 屬性是設(shè)置CAGradientLayer的漸變顏色(此Demo是從黑-->白-->黑)予权。
locations 屬性是相對于 colors 設(shè)置的,此Demo中l(wèi)ocations值的含義是 按顏色漸變方向劃分 浪册,從(0 -> 0.25)部分是黑色扫腺,從(0.25 -> 0.5)部分是黑到白的漸變過程,以此類推0.75的含義村象。
注意
1.CAGradientLayer 默認的漸變方向是從上到下笆环,即垂直方向攒至。
2.colors 是個NSArray類型,只能存對象躁劣,所以需要將CGColor轉(zhuǎn)換一下迫吐,此屬性可設(shè)置多個值(1個,2個账忘,3個等...志膀,都行),此Demo的滑動解鎖效果只需要 兩種 顏色的漸變鳖擒,所以設(shè)置了三個值溉浙,實際值可根據(jù)需求設(shè)置。
3.設(shè)置好 colors 要設(shè)置好與之相對應(yīng)的 locations 值
4.如果要改變 CAGradientLayer 的漸變方向蒋荚,則要顯式的給 startPoint和 endPoint 兩個屬性賦值戳稽。
如果要改為水平方向,則需要改成
gradientLayer.startPoint = CGPointMake(0, 0.5);
gradientLayer.endPoint = CGPointMake(1, 0.5)
修改之后的效果圖:
startPoint期升,endPoint原理解析
既然 CAGradientLayer 可以繪制出漸變顏色的效果惊奇,那自然有顏色漸變的方向,所以這兩個屬性的作用就是設(shè)置顏色漸變的起始點和結(jié)束點播赁,這兩個屬性共同決定了顏色漸變的方向:
接下來來個CAGradientLayer的動效Demo(只需要在上面的代碼添加幾句即可)
- (void)viewDidLoad {
[super viewDidLoad];
self.view.backgroundColor = [UIColor grayColor];
// 漸變Layer
CAGradientLayer *gradientLayer = [CAGradientLayer layer];
[self.view.layer addSublayer:gradientLayer];
gradientLayer.frame = CGRectMake(0, 200, self.view.width, 64);
gradientLayer.colors = @[
(__bridge id)[UIColor blackColor].CGColor,
(__bridge id)[UIColor whiteColor].CGColor,
(__bridge id)[UIColor blackColor].CGColor, ];
gradientLayer.locations = @[@0.25,@0.5,@0.75];
// 添加部分
CABasicAnimation *basicAnimation = [CABasicAnimation animationWithKeyPath:@"locations"];
basicAnimation.fromValue = @[@0, @0, @0.25];
basicAnimation.toValue = @[@0.75, @1, @1];
basicAnimation.duration = 2.5;
basicAnimation.repeatCount = HUGE;
[gradientLayer addAnimation:basicAnimation forKey:nil];
}
解析:
- 將keyPath賦值為“l(fā)ocations”是讓CAGradientLayer的locations屬性做動畫赊时,因為locations對應(yīng)著顏色,那么顏色也會跟著動行拢,最終的顯示效果就是:
疑問:但是如何將顏色漸變的動畫作用在UILabel的文字上呢 祖秒?
1.其實非常簡單,就是讓UILabel上的文字稱為CAGradientLayer的遮罩即可舟奠。
再來修改下代碼
- (void)viewDidLoad {
[super viewDidLoad];
self.view.backgroundColor = [UIColor grayColor];
// 漸變Layer
CAGradientLayer *gradientLayer = [CAGradientLayer layer];
[self.view.layer addSublayer:gradientLayer];
gradientLayer.frame = CGRectMake(0, 200, self.view.width, 64);
gradientLayer.colors = @[
(__bridge id)[UIColor blackColor].CGColor,
(__bridge id)[UIColor whiteColor].CGColor,
(__bridge id)[UIColor blackColor].CGColor, ];
gradientLayer.locations = @[@0.25,@0.5,@0.75];
// 添加部分
CABasicAnimation *basicAnimation = [CABasicAnimation animationWithKeyPath:@"locations"];
basicAnimation.fromValue = @[@0, @0, @0.25];
basicAnimation.toValue = @[@0.75, @1, @1];
basicAnimation.duration = 2.5;
basicAnimation.repeatCount = HUGE;
[gradientLayer addAnimation:basicAnimation forKey:nil];
// 第二次添加部分
UILabel *unlock = [[UILabel alloc] initWithFrame:gradientLayer.bounds];
// 必需要強引用保存unlock竭缝,此句也可以用[self.view addSubview:unlock]來替代;
self.unlock = unlock;
unlock.alpha = 0.5;
unlock.text = @"滑動來解鎖 >>";
unlock.textAlignment = NSTextAlignmentCenter;
unlock.font = [UIFont boldSystemFontOfSize:30];
gradientLayer.mask = unlock.layer;
}
代碼解析:
1.self.unlock = unlock; 用強引用保存label (@property (nonatomic, strong)UILabel *unlock;) ,防止 label dealloc沼瘫,如果label被銷毀抬纸,則label沒有了delegate。
為什么要強引用 unlock 標簽 ?
當一個控件(UIiew,UIlabel,UIbutton)創(chuàng)建時,系統(tǒng)會自動創(chuàng)建一個與之相對應(yīng)的layer耿戚,layer怎么顯示湿故,實際是與之對應(yīng)的控件相關(guān)的,layer與之對應(yīng)的控件是delegate關(guān)系膜蛔,即layer.delegate=當前控件坛猪,在系統(tǒng)創(chuàng)建layer之后,layer的delegate會執(zhí)行 - (void)drawLayer:(CALayer *)layer inContext:(CGContextRef)context 方法繪制圖層來顯示給用戶看皂股,當控件銷毀了墅茉,則不會執(zhí)行此方法了,那么layer上什么也沒有,又因為控件創(chuàng)建的默認色為clearColor(如果設(shè)置了backgroundColor為不透明就斤,則layer也會不透明),那么layer也會全透明(UIImageView比較特殊悍募,除外)。在此例中如果不強引用保存unlock洋机,執(zhí)行完viewDidload方法后unlock就會銷毀坠宴,如果unlock銷毀了,那么unlock相對的layer就是全透明绷旗,那么gradientLayer也會全透明喜鼓,即不強引用unlock的最終顯示效果是 屏幕上什么都看不見。
最終滑動解鎖效果圖:
關(guān)于CAGradientLayer的屬性詳細解析可參考CAGradientLayer的一些屬性解析
三.maskView配合CAShapeLayer使用
這個Demo沒啥可講的刁标,自己看下源碼颠通,先上效果圖址晕,再上代碼膀懈。
#import "UIImage+DDF.h"
#define DEGREES(degrees) ((M_PI * (degrees))/ 180.f)
@interface ViewControllerSix ()
@property (nonatomic, strong) UIView *showView;
@property (nonatomic, strong) CAShapeLayer *maskLayer;
@end
@implementation ViewControllerSix
- (void)handlePan:(UIPanGestureRecognizer *)recognizer
{
// 拖拽
CGPoint translation = [recognizer translationInView:self.view];
recognizer.view.center = CGPointMake(recognizer.view.center.x + translation.x,
recognizer.view.center.y + translation.y);
[recognizer setTranslation:CGPointMake(0, 0) inView:self.view];
// 關(guān)閉CoreAnimation的隱式動畫,如果開啟隱式動畫谨垃,會出現(xiàn)卡頓現(xiàn)象启搂。
[CATransaction setDisableActions:YES];
_maskLayer.position = recognizer.view.center;
}
- (void)viewDidLoad
{
[super viewDidLoad];
UIImageView *imageView = [[UIImageView alloc] initWithFrame:self.view.bounds];
imageView.image = [UIImage imageNamed:@"Slice"];
[self.view addSubview:imageView];
_maskLayer = [CAShapeLayer layer];
// 利用貝塞爾曲線創(chuàng)建一個圓
UIBezierPath *path = [UIBezierPath bezierPathWithArcCenter:CGPointMake(0, 0)
radius:100
startAngle:DEGREES(0)
endAngle:DEGREES(360)
clockwise:YES];
// 獲取path
_maskLayer.path = path.CGPath;
_maskLayer.position = CGPointMake(_showView.bounds.size.width/2.f,
_showView.bounds.size.height/2.f);
_maskLayer.fillColor = [UIColor whiteColor].CGColor;
_maskLayer.position = self.view.center;
UIView *blurView = [[UIView alloc] initWithFrame:self.view.bounds];
blurView.backgroundColor = [UIColor blackColor];
[self.view addSubview:blurView];
// 只顯示圓形部分
blurView.layer.mask = _maskLayer;
blurView.layer.contents = (__bridge id)([[UIImage imageNamed:@"Slice"] imgWithBlur].CGImage);
/*
透明的View,用于maskView中的ShapeLayer的參考View(用于拖拽)
*/
_showView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 200, 200)];
_showView.backgroundColor = [UIColor clearColor];
_showView.center = self.view.center;
[self.view addSubview:_showView];
UIPanGestureRecognizer *recognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(handlePan:)];
[_showView addGestureRecognizer:recognizer];
}
@end
上述所有Demo源碼地址MaskViewDemo