美文网首页iOS~ 贝塞尔曲线:UIBezierPath和CAShapeLayer
ios ~ UIBezierPath 贝塞尔曲线,使用其appe

ios ~ UIBezierPath 贝塞尔曲线,使用其appe

作者: 阳光下的叶子呵 | 来源:发表于2022-10-20 14:28 被阅读0次

    在此之前,我们先来说说需求:
    之前我们都是使用UIBezierPathCAShapeLayer,设置mask遮罩层,再显示mask范围内的视图,其他部分不显示;
    但是现在,我们想要:一个范围内显示清晰图像,其他部分显示模糊图像(或颜色灰暗的图像),该怎么设置呢?
    下面我们来试一下:

    镂空图(高亮部分).png
    ①原理:比如,我们想要在一个页面上实现以上要求,创建一个镂空图,在页面覆盖一个透明的UIView,在创建layer之前,改变这个view的颜色为黑色半透明,如下面代码:使用UIBezierPath的方法appendPath:实现镂空图的描绘(注意,不要忘了:_mask_Layer.fillRule = kCAFillRuleEvenOdd;
    • UIBezierPath 有个原生的方法- (void)appendPath:(UIBezierPath *)bezierPath, 这个方法作用是俩个路径有叠加的部分则会镂空。这个方法实现原理应该是path的FillRule 默认是FillRuleEvenOdd。
      CALayer 有一个fillRule属性的规则就有kCAFillRuleEvenOdd, 而EvenOdd 是一个奇偶规则,奇数则显示,偶数则不显示,叠加则是偶数故不显示。

    GW_NewUserGuidance_FirstStepView.m:

    @interface GW_NewUserGuidance_FirstStepView ()
    
    @property (nonatomic, strong) UILabel   *titleL;
    @property (nonatomic, strong) UIButton  *skipBut;
    @property (nonatomic, strong) CAShapeLayer *mask_Layer;
    @property (nonatomic, strong) UIButton  *nextBut;
    
    // 历史记录:
    @property (nonatomic, strong) CAShapeLayer  *history_lineLayer; // 虚线边框
    
    @end
    
    @implementation GW_NewUserGuidance_FirstStepView
    
    - (instancetype)initWithFrame:(CGRect)frame {
        self = [super initWithFrame:frame];
        if (self) {
            self.backgroundColor = UIColor.clearColor;
    //        self.backgroundColor = RGBA(0, 0, 0, 0.6);
            [self setupUI];
        }
        return self;
    }
    
    // 跳过:
    - (void)skip_TeachStepsAction {
        
        // 保存在本地一个判断值,表示已经显示过:
        [[NSUserDefaults standardUserDefaults] setObject:@"1" forKey:@"is_skip_NewUserGuidance"];
        [[NSUserDefaults standardUserDefaults] synchronize];
        
        [self removeFromSuperview];
    }
    
    
    - (void)refreshUI {
        
        self.backgroundColor = RGBA(0, 0, 0, 0.6);
        
        [self.mask_Layer removeFromSuperlayer];
        [self.history_lineLayer removeFromSuperlayer];
        
        
        UIBezierPath *backBezierPath = [UIBezierPath
                                            bezierPathWithRoundedRect:CGRectMake(0, 0, [UIScreen mainScreen].bounds.size.width, [UIScreen mainScreen].bounds.size.height)
                                            byRoundingCorners:UIRectCornerTopLeft | UIRectCornerTopRight
                                            cornerRadii:CGSizeMake([UIScreen mainScreen].bounds.size.width/375*0, [UIScreen mainScreen].bounds.size.width/375*0)];
    
        /**
         * UIBezierPath 有个原生的方法- (void)appendPath:(UIBezierPath *)bezierPath, 这个方法作用是俩个路径有叠加的部分则会镂空.
         * 这个方法实现原理应该是path的FillRule 默认是FillRuleEvenOdd(CALayer 有一个fillRule属性的规则就有kCAFillRuleEvenOdd), 而EvenOdd 是一个奇偶规则,奇数则显示,偶数则不显示.叠加则是偶数故不显示
         */
        // 历史记录 贝塞尔path:UIBezierPath(清晰 镂空layer)
    //    UIBezierPath *backBezierPath = [UIBezierPath bezierPathWithRect:self.bounds];
        UIBezierPath *history_Path = [UIBezierPath bezierPathWithRoundedRect:CGRectMake([UIScreen mainScreen].bounds.size.width/375*2, k_Height_StatusBar + [UIScreen mainScreen].bounds.size.width/375*(27+ 46 + 60), [UIScreen mainScreen].bounds.size.width/2, [UIScreen mainScreen].bounds.size.width/375*80) cornerRadius:[UIScreen mainScreen].bounds.size.width/375*5];    
        
        [backBezierPath appendPath:history_Path]; // 可以多个path叠加(同一个path之中可以添加多个子path)
        // [backBezierPath appendPath:matchCalendar_Path];
        // [backBezierPath appendPath:often_Path];
        
        // 创建 底层layer
        _mask_Layer = [CAShapeLayer layer];
        _mask_Layer.path        = [backBezierPath CGPath];
        _mask_Layer.fillRule = kCAFillRuleEvenOdd; // 这个属性fillRule要加上,有时候,防止默认不生效
        // 遮罩
        self.layer.mask = self.mask_Layer;
        
        
        /** 给镂空图 添加一个虚线边框: */
        // 边界框 layer(可以设置成 虚线,将镂空位置框起来)
        UIBezierPath *history_linePath = [UIBezierPath bezierPathWithRoundedRect:CGRectMake([UIScreen mainScreen].bounds.size.width/375*1, k_Height_StatusBar + [UIScreen mainScreen].bounds.size.width/375*(27+ 46 + 60 -1), [UIScreen mainScreen].bounds.size.width/2+[UIScreen mainScreen].bounds.size.width/375*2, [UIScreen mainScreen].bounds.size.width/375*(80 + 2)) cornerRadius:[UIScreen mainScreen].bounds.size.width/375*5];
        
        _history_lineLayer = [[CAShapeLayer alloc] init];
        _history_lineLayer.lineWidth = [UIScreen mainScreen].bounds.size.width/375*1;
        // 颜色
        _history_lineLayer.strokeColor = [UIColor whiteColor].CGColor;
        // 背景填充色
        _history_lineLayer.fillColor = UIColor.clearColor.CGColor;
        _history_lineLayer.lineDashPattern = @[@4, @4];
        _history_lineLayer.path = [history_linePath CGPath];
        [self.layer addSublayer:self.history_lineLayer];
        
        self.titleL.hidden = NO;
        self.skipBut.hidden = NO;
        self.nextBut.hidden = NO;
    }
    
    - (void)setupUI {
        
        _titleL = [[UILabel alloc] init];
        _titleL.text = @"新手引导";
        _titleL.textColor = UIColor.whiteColor;
        _titleL.textAlignment = NSTextAlignmentLeft;
        _titleL.font = [UIFont systemFontOfSize:[UIScreen mainScreen].bounds.size.width/375*18 weight:UIFontWeightBlack];
        [self addSubview:self.titleL];
        [self.titleL makeConstraints:^(MASConstraintMaker *make) {
            make.top.mas_equalTo(self.mas_top).offset(k_Height_StatusBar);
            make.left.mas_equalTo(self.mas_left).offset([UIScreen mainScreen].bounds.size.width/375*20);
        }];
        
        _skipBut = [UIButton buttonWithType:UIButtonTypeCustom];
        [_skipBut setTitle:@"跳过" forState:UIControlStateNormal];
        [_skipBut setTitleColor:UIColor.whiteColor forState:UIControlStateNormal];
        _skipBut.titleLabel.font = [UIFont systemFontOfSize:[UIScreen mainScreen].bounds.size.width/375*16 weight:UIFontWeightMedium];
        _skipBut.contentHorizontalAlignment =UIControlContentHorizontalAlignmentRight;
        [self.skipBut addTarget:self action:@selector(skip_TeachStepsAction) forControlEvents:UIControlEventTouchUpInside];
        [self addSubview:self.skipBut];
        [self.skipBut makeConstraints:^(MASConstraintMaker *make) {
            make.centerY.equalTo(self.titleL);
            make.right.mas_equalTo(self.mas_right).offset(-[UIScreen mainScreen].bounds.size.width/375*20);
            make.width.mas_equalTo([UIScreen mainScreen].bounds.size.width/375*50);
            make.height.mas_equalTo([UIScreen mainScreen].bounds.size.width/375*20);
        }];
        if (self.skipBut.titleLabel.text.length > 0) {
            NSDictionary *attributeDic = @{NSUnderlineStyleAttributeName:[NSNumber numberWithInteger:NSUnderlineStyleSingle]};
            NSMutableAttributedString *attributedString = [[NSMutableAttributedString alloc] initWithString:self.skipBut.titleLabel.text attributes:attributeDic];
            self.skipBut.titleLabel.attributedText = attributedString;
        }
        
        _nextBut = [UIButton buttonWithType:UIButtonTypeCustom];
        [_nextBut setTitle:@"下一步" forState:UIControlStateNormal];
        [_nextBut setTitleColor:UIColor.whiteColor forState:UIControlStateNormal];
        _nextBut.titleLabel.font = [UIFont systemFontOfSize:[UIScreen mainScreen].bounds.size.width/375*14 weight:UIFontWeightMedium];
        _nextBut.layer.borderColor = UIColor.whiteColor.CGColor;
        _nextBut.layer.borderWidth = [UIScreen mainScreen].bounds.size.width/375*2;
        self.nextBut.layer.masksToBounds = YES;
        self.nextBut.layer.cornerRadius = [UIScreen mainScreen].bounds.size.width/375*4;
        [self addSubview:self.nextBut];
        [self.nextBut makeConstraints:^(MASConstraintMaker *make) {
            make.centerX.equalTo(self);
            make.top.mas_equalTo(self.mas_top).offset(k_Height_StatusBar + [UIScreen mainScreen].bounds.size.width/375*((292 + 20) + (36 + 107 - 5-3) + 40+5 + 100 + 20));
            make.width.mas_equalTo([UIScreen mainScreen].bounds.size.width/375*60);
            make.height.mas_equalTo([UIScreen mainScreen].bounds.size.width/375*25);
        }];
        [self.nextBut addTarget:self action:@selector(guidance_NextAction) forControlEvents:UIControlEventTouchUpInside];
        
        self.titleL.hidden = YES;
        self.skipBut.hidden = YES;
        self.nextBut.hidden = YES;
    }
    
    
    @end
    
    
    

    相关文章

      网友评论

        本文标题:ios ~ UIBezierPath 贝塞尔曲线,使用其appe

        本文链接:https://www.haomeiwen.com/subject/wfcmzrtx.html