最近遇到一個(gè)需求犬耻,label樣式設(shè)置如下,并不是四個(gè)圓角执泰,而是右上和右下設(shè)置圓角枕磁。
代碼很簡(jiǎn)單,寫(xiě)一個(gè)方法术吝,需要裁剪的控件調(diào)用以下方法即可计济。
-(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;
}
- (instancetype)bezierPathWithRoundedRect:(CGRect)rect byRoundingCorners:(UIRectCorner)corners cornerRadii:(CGSize)cornerRadii;在這個(gè)方法中,第二個(gè)參數(shù)UIRectCorner是一個(gè)枚舉類型排苍,即你需要指定裁剪為圓角的view的角沦寂。
typedef NS_OPTIONS(NSUInteger, UIRectCorner) {
UIRectCornerTopLeft = 1 << 0, //左上角
UIRectCornerTopRight = 1 << 1, //右上角
UIRectCornerBottomLeft = 1 << 2, //左下角
UIRectCornerBottomRight = 1 << 3, //右下角
UIRectCornerAllCorners = ~0UL //四個(gè)角
};
如果你想裁剪多個(gè)不同的角,可以用"|"進(jìn)行組合淘衙,傳入多個(gè)即可传藏。方法中的CAShapeLayer是一個(gè)神奇的子類,可以定制很多有趣的UI控件,具體可以參考簡(jiǎn)書(shū)里的這篇文章放肆的使用UIBezierPath和CAShapeLayer畫(huà)各種圖形
從結(jié)果來(lái)看符合要求毯侦,但是這篇文章的重點(diǎn)不在這西壮,而是我下面要說(shuō)的事情,也是我實(shí)現(xiàn)這個(gè)需求過(guò)程中遇到的問(wèn)題叫惊,記錄一下款青。
這個(gè)需求是要在兩個(gè)頁(yè)面實(shí)現(xiàn)的,方法和調(diào)用都一致霍狰。只是這兩個(gè)頁(yè)面的我創(chuàng)建label的方式不一樣抡草,這也才導(dǎo)致了問(wèn)題的發(fā)生。第一個(gè)頁(yè)面的我是用xib拖的label蔗坯。第二個(gè)頁(yè)面我是用純代碼創(chuàng)建的label康震。下面就分兩種情況具體說(shuō)一下。
xib創(chuàng)建的label
這種情形下很簡(jiǎn)單宾濒,我在xib相關(guān)聯(lián)的.m文件中awakeFromNib方法中調(diào)用方法即可腿短,運(yùn)行結(jié)果也正常。
- (void)awakeFromNib {
[super awakeFromNib];
// Initialization code
[self changeLabelStyle:self.pic_tag_label1];
[self changeLabelStyle:self.pic_tag_label2];
[self changeLabelStyle:self.pic_tag_label3];
}
但是第二個(gè)頁(yè)面用純代碼創(chuàng)建的label就出了問(wèn)題了绘梦。
純代碼創(chuàng)建的label
ps:因?yàn)楫?dāng)時(shí)是在項(xiàng)目工程中發(fā)現(xiàn)的問(wèn)題橘忱,已經(jīng)解決上傳了,所以我后來(lái)寫(xiě)了個(gè)簡(jiǎn)單的demo卸奉,效果跟我預(yù)期的差不多钝诚。
代碼如下,是創(chuàng)建一個(gè)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 = @"圓角測(cè)試";
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視圖查看拧略。
再打印label的信息,控制臺(tái)顯示如下
Printing description of $3:
<UILabel: 0x7f83fc413740; frame = (100 100; 100 40); text = '圓角測(cè)試'; userInteractionEnabled = NO; layer = <_UILabelLayer: 0x6080002877b0>>
(lldb)
label其實(shí)是存在的瘪弓,但是不能顯示垫蛆,自然就聯(lián)想到了調(diào)用裁剪圓角的方法,肯定是這里出了問(wèn)題杠茬,在這個(gè)方法里月褥,傳進(jìn)的是label控件弛随,涉及到label的frame瓢喉,所以我就打印了一下label的frame,結(jié)果如下
再回過(guò)頭來(lái)看上面的代碼舀透,我是用masonry設(shè)置完label的約束之后調(diào)用的方法栓票,我在想,是不是masonry設(shè)置約束block中的處理是放在另一個(gè)線程中異步進(jìn)行的,block還沒(méi)執(zhí)行完就已經(jīng)走到了下面使用frame的代碼走贪,所以把方法的調(diào)用寫(xiě)在了設(shè)置約束的block里佛猛,但是label依然不能正常顯示,label的frame打印結(jié)果依舊是上面的結(jié)果坠狡。
后來(lái)和朋友說(shuō)了這事继找,自己也在網(wǎng)上查了資料,才發(fā)現(xiàn):
使用masonry的實(shí)質(zhì)還是調(diào)用了ios7以后的autolayout逃沿,如果要更新frame婴渡,需要調(diào)用layoutIfNeeded函數(shù)進(jìn)行布局,然后所約束的控件才會(huì)按照約束條件凯亮,生成當(dāng)前布局相應(yīng)的frame和bounds边臼。這樣就可以利用這兩個(gè)屬性來(lái)進(jìn)行圖片圓角剪裁。而調(diào)用layoutIfNeeded的目的是讓系統(tǒng)調(diào)用layoutSubviews方法假消,我們也可以直接在這個(gè)方法里獲取frame柠并,因?yàn)檫@時(shí)候開(kāi)始layout subviews,Masonry已經(jīng)計(jì)算出了真實(shí)的frame富拗。
最后我在調(diào)用裁剪圓角方法的前面調(diào)用了layoutIfNeeded方法臼予,label成功顯示,此時(shí)打印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 = @"圓角測(cè)試";
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;
}
附上關(guān)于autolayout更新幾個(gè)方法的區(qū)別:
- setNeedsLayout:告知頁(yè)面需要更新瘟栖,但是不會(huì)立刻開(kāi)始更新。執(zhí)行后會(huì)立刻調(diào)用layoutSubviews谅阿。
- layoutIfNeeded:告知頁(yè)面布局立刻更新半哟。所以一般都會(huì)和setNeedsLayout一起使用。如果希望立刻生成新的frame需要調(diào)用此方法签餐,利用這點(diǎn)寓涨,動(dòng)畫(huà)可以在更新布局后直接使用這個(gè)方法讓動(dòng)畫(huà)生效。
- layoutSubviews:系統(tǒng)重寫(xiě)布局
- setNeedsUpdateConstraints:告知需要更新約束氯檐,但是不會(huì)立刻開(kāi)始
- updateConstraintsIfNeeded:告知立刻更新約束
- updateConstraints:系統(tǒng)更新約束