在此之前,我们先来说说需求:
之前我们都是使用UIBezierPath
和CAShapeLayer
,设置mask
遮罩层,再显示mask
范围内的视图,其他部分不显示;
但是现在,我们想要:一个范围内显示清晰图像
,其他部分显示模糊图像(或颜色灰暗的图像)
,该怎么设置呢?
下面我们来试一下:
①原理:比如,我们想要在一个页面上实现以上要求,创建一个镂空图
,在页面覆盖一个透明的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
网友评论