maskView使用進(jìn)階(配合CAGradientLayer,CAShapeLayer使用)

上一篇文章介紹了maskView的原理和基本使用
接下來介紹下maskView的進(jìn)階使用

一.利用maskView使用多種圖片做漸變切換動(dòng)畫

1.素材

base

background

mask

mask1
    // 上述素材按照順序分別是‘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默認(rèn)色為透明(clearColor),如果picOne和picTwo不存在時(shí),由于mask是透明,切mask又是upGround的maskView,則upGround也會透明,即效果圖只會看到baseGround。在此例中一開始mask有picOne和picTwo兩個(gè)子View,且picOne和picTwo顯示在mask上的部分不是透明部分,所以一開始效果圖只會看到backGround.

  • 圖片漸變動(dòng)畫實(shí)現(xiàn)原理:
    隨著picOne和picTwo的上下部分移動(dòng),最終的效果是picOne和picTwo顯示在mask上的都是透明部分,當(dāng)顯示在mask上的控件透明時(shí),則mask也會透明,那么backGround也會透明,最終的效果圖就是逐漸看不到backGround,然后顯示baseGround.

運(yùn)行效果圖

效果圖

二.maskView配合CAGradientLayer使用

iPhone滑動(dòng)解鎖效果

先來個(gè)Demo來解釋下CAGradientLayer吧,先了解下CAGradientLayer是個(gè)啥玩意,

- (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];
 }

運(yùn)行效果圖:

效果圖

CAGradientLayer可用來處理顏色漸變,它的漸變色也可以做隱式動(dòng)畫

此例用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 默認(rèn)的漸變方向是從上到下,即垂直方向。

2.colors 是個(gè)NSArray類型,只能存對象,所以需要將CGColor轉(zhuǎn)換一下,此屬性可設(shè)置多個(gè)值(1個(gè),2個(gè),3個(gè)等...,都行),此Demo的滑動(dòng)解鎖效果只需要 兩種 顏色的漸變,所以設(shè)置了三個(gè)值,實(shí)際值可根據(jù)需求設(shè)置。

3.設(shè)置好 colors 要設(shè)置好與之相對應(yīng)的 locations

4.如果要改變 CAGradientLayer 的漸變方向,則要顯式的給 startPointendPoint 兩個(gè)屬性賦值。

如果要改為水平方向,則需要改成

             gradientLayer.startPoint = CGPointMake(0, 0.5);
             gradientLayer.endPoint = CGPointMake(1, 0.5)           

修改之后的效果圖:

效果圖
startPoint,endPoint原理解析

既然 CAGradientLayer 可以繪制出漸變顏色的效果,那自然有顏色漸變的方向,所以這兩個(gè)屬性的作用就是設(shè)置顏色漸變的起始點(diǎn)和結(jié)束點(diǎn),這兩個(gè)屬性共同決定了顏色漸變的方向:

原理分析圖


接下來來個(gè)CAGradientLayer的動(dòng)效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];
    
 }

解析:

  1. 將keyPath賦值為“l(fā)ocations”是讓CAGradientLayer的locations屬性做動(dòng)畫,因?yàn)閘ocations對應(yīng)著顏色,那么顏色也會跟著動(dòng),最終的顯示效果就是:
效果圖

疑問:但是如何將顏色漸變的動(dòng)畫作用在UILabel的文字上呢 ?

1.其實(shí)非常簡單,就是讓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];
    // 必需要強(qiáng)引用保存unlock,此句也可以用[self.view addSubview:unlock]來替代;
    self.unlock = unlock;   
    unlock.alpha = 0.5;
    unlock.text = @"滑動(dòng)來解鎖 >>";
    unlock.textAlignment = NSTextAlignmentCenter;
    unlock.font = [UIFont boldSystemFontOfSize:30];
    gradientLayer.mask = unlock.layer;
 }
 
 

代碼解析:

1.self.unlock = unlock; 用強(qiáng)引用保存label (@property (nonatomic, strong)UILabel *unlock;) ,防止 label dealloc,如果label被銷毀,則label沒有了delegate。

為什么要強(qiáng)引用 unlock 標(biāo)簽 ?

當(dāng)一個(gè)控件(UIiew,UIlabel,UIbutton)創(chuàng)建時(shí),系統(tǒng)會自動(dòng)創(chuàng)建一個(gè)與之相對應(yīng)的layer,layer怎么顯示,實(shí)際是與之對應(yīng)的控件相關(guān)的,layer與之對應(yīng)的控件是delegate關(guān)系,即layer.delegate=當(dāng)前控件,在系統(tǒng)創(chuàng)建layer之后,layer的delegate會執(zhí)行 - (void)drawLayer:(CALayer *)layer inContext:(CGContextRef)context 方法繪制圖層來顯示給用戶看,當(dāng)控件銷毀了,則不會執(zhí)行此方法了,那么layer上什么也沒有,又因?yàn)榭丶?chuàng)建的默認(rèn)色為clearColor(如果設(shè)置了backgroundColor為不透明,則layer也會不透明),那么layer也會全透明(UIImageView比較特殊,除外)。在此例中如果不強(qiáng)引用保存unlock,執(zhí)行完viewDidload方法后unlock就會銷毀,如果unlock銷毀了,那么unlock相對的layer就是全透明,那么gradientLayer也會全透明,即不強(qiáng)引用unlock的最終顯示效果是 屏幕上什么都看不見。

最終滑動(dòng)解鎖效果圖:

效果圖

關(guān)于CAGradientLayer的屬性詳細(xì)解析可參考CAGradientLayer的一些屬性解析

三.maskView配合CAShapeLayer使用

這個(gè)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的隱式動(dòng)畫,如果開啟隱式動(dòng)畫,會出現(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)建一個(gè)圓
    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

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Core Animation Core Animation,中文翻譯為核心動(dòng)畫,它是一組非常強(qiáng)大的動(dòng)畫處理API,...
    45b645c5912e閱讀 3,154評論 0 21
  • 發(fā)現(xiàn) 關(guān)注 消息 iOS 第三方庫、插件、知名博客總結(jié) 作者大灰狼的小綿羊哥哥關(guān)注 2017.06.26 09:4...
    肇東周閱讀 15,197評論 4 61
  • 轉(zhuǎn)載:http://www.itdecent.cn/p/32fcadd12108 每個(gè)UIView有一個(gè)伙伴稱為l...
    F麥子閱讀 6,569評論 0 13
  • 傍晚,伴著美麗的落霞,與老友相約,閑庭散步暢聊人生,當(dāng)作一種送別,也算作一份作答,更留作一次記憶,區(qū)區(qū)公里之路,卻...
    落水有聲閱讀 811評論 0 1
  • 以前一直覺得一個(gè)人年輕的時(shí)候做事風(fēng)風(fēng)火火,斗志昂揚(yáng),怎么過了年月后卻突然跟沒有出息的一樣,現(xiàn)在我也許知道答案了。人...
    高天明月55閱讀 334評論 0 0

友情鏈接更多精彩內(nèi)容