专注iOS开发iOS开发 技术集锦iOS学习开发

iOS 裁剪View指定的某几个角为圆角以及遇到的问题

2017-04-14  本文已影响2165人  陨之希留leo

最近遇到一个需求,label样式设置如下,并不是四个圆角,而是右上和右下设置圆角。

指定裁剪圆角

代码很简单,写一个方法,需要裁剪的控件调用以下方法即可。

-(void)changeLabelStyle:(UILabel *)label{
UIBezierPath *maskPath = [UIBezierPath bezierPathWithRoundedRect:label.bounds byRoundingCorners:UIRectCornerTopRight | UIRectCornerBottomRight cornerRadii:CGSizeMake(20, 20)];
CAShapeLayer *maskLayer = [[CAShapeLayer alloc] init];
maskLayer.frame = label.bounds;
maskLayer.path = maskPath.CGPath;
label.layer.mask = maskLayer;
}
typedef NS_OPTIONS(NSUInteger, UIRectCorner) {
UIRectCornerTopLeft     = 1 << 0,  //左上角
UIRectCornerTopRight    = 1 << 1, //右上角
UIRectCornerBottomLeft  = 1 << 2, //左下角
UIRectCornerBottomRight = 1 << 3, //右下角
UIRectCornerAllCorners  = ~0UL   //四个角
};

如果你想裁剪多个不同的角,可以用"|"进行组合,传入多个即可。方法中的CAShapeLayer是一个神奇的子类,可以定制很多有趣的UI控件,具体可以参考简书里的这篇文章放肆的使用UIBezierPath和CAShapeLayer画各种图形


从结果来看符合要求,但是这篇文章的重点不在这,而是我下面要说的事情,也是我实现这个需求过程中遇到的问题,记录一下。

这个需求是要在两个页面实现的,方法和调用都一致。只是这两个页面的我创建label的方式不一样,这也才导致了问题的发生。第一个页面的我是用xib拖的label。第二个页面我是用纯代码创建的label。下面就分两种情况具体说一下。

xib创建的label

这种情形下很简单,我在xib相关联的.m文件中awakeFromNib方法中调用方法即可,运行结果也正常。

- (void)awakeFromNib {
[super awakeFromNib];
// Initialization code
[self changeLabelStyle:self.pic_tag_label1];
[self changeLabelStyle:self.pic_tag_label2];
[self changeLabelStyle:self.pic_tag_label3];
}
xib运行结果

但是第二个页面用纯代码创建的label就出了问题了。

纯代码创建的label

ps:因为当时是在项目工程中发现的问题,已经解决上传了,所以我后来写了个简单的demo,效果跟我预期的差不多。

代码如下,是创建一个tableview,自定义headerview,以下是自定义headerview代码。
- (UIView *)creatHeaderView{

UIView *topView = [[UIView alloc]initWithFrame:CGRectMake(0, 0, [UIScreen mainScreen].bounds.size.width, 240)];

UILabel *label = [[UILabel alloc]init];
label.backgroundColor = [UIColor redColor];
label.text = @"圆角测试";
label.textAlignment = NSTextAlignmentCenter;
[topView addSubview:label];

[label mas_makeConstraints:^(MASConstraintMaker *make) {
   
    make.size.mas_equalTo(CGSizeMake(100, 40));
    make.leading.equalTo(topView.mas_leading).offset(100);
    make.top.equalTo(topView.mas_top).offset(100);
    
}];

[self changeLabelStyle:label];

return  topView;

}

运行结果

label不能正常显示,接着切换3D视图查看。

3D视图

再打印label的信息,控制台显示如下

Printing description of $3:
<UILabel: 0x7f83fc413740; frame = (100 100; 100 40); text = '圆角测试';       userInteractionEnabled = NO; layer = <_UILabelLayer: 0x6080002877b0>>
(lldb) 

label其实是存在的,但是不能显示,自然就联想到了调用裁剪圆角的方法,肯定是这里出了问题,在这个方法里,传进的是label控件,涉及到label的frame,所以我就打印了一下label的frame,结果如下

打印label结果

再回过头来看上面的代码,我是用masonry设置完label的约束之后调用的方法,我在想,是不是masonry设置约束block中的处理是放在另一个线程中异步进行的,block还没执行完就已经走到了下面使用frame的代码,所以把方法的调用写在了设置约束的block里,但是label依然不能正常显示,label的frame打印结果依旧是上面的结果。

后来和朋友说了这事,自己也在网上查了资料,才发现:
使用masonry的实质还是调用了ios7以后的autolayout,如果要更新frame,需要调用layoutIfNeeded函数进行布局,然后所约束的控件才会按照约束条件,生成当前布局相应的frame和bounds。这样就可以利用这两个属性来进行图片圆角剪裁。而调用layoutIfNeeded的目的是让系统调用layoutSubviews方法,我们也可以直接在这个方法里获取frame,因为这时候开始layout subviews,Masonry已经计算出了真实的frame。

最后我在调用裁剪圆角方法的前面调用了layoutIfNeeded方法,label成功显示,此时打印label的frame也是正确的。

- (UIView *)creatHeaderView{

UIView *topView = [[UIView alloc]initWithFrame:CGRectMake(0, 0, [UIScreen mainScreen].bounds.size.width, 240)];
UILabel *label = [[UILabel alloc]init];
label.backgroundColor = [UIColor redColor];
label.text = @"圆角测试";
label.textAlignment = NSTextAlignmentCenter;
[topView addSubview:label];
[label mas_makeConstraints:^(MASConstraintMaker *make) {
    make.size.mas_equalTo(CGSizeMake(100, 40));
    make.leading.equalTo(topView.mas_leading).offset(100);
    make.top.equalTo(topView.mas_top).offset(100);
}];
[label layoutIfNeeded];
[self changeLabelStyle:label];

return  topView;
}

label正常显示 此时label打印结果

附上关于autolayout更新几个方法的区别:

上一篇下一篇

猜你喜欢

热点阅读