俗話說UI有三寶,邊框陰影加圓角苍日。目前移動開發(fā)基本都是扁平化風格惭聂,很多UI設(shè)計都是邊框陰影加圓角的套路,正常我們使用系統(tǒng)的layer就可以滿足要求相恃,雖然性能有些問題辜纲,但是始終能解決問題。但是如果涉及到某個角切圓角拦耐,或者在切指定某個圓角的同時加邊框或者加陰影就比較蛋疼了耕腾。
1 先介紹一下切圓角的場景
切圓角的方式一般有兩種。
第一種杀糯,使用 UIView 內(nèi)嵌的 layer扫俺,直接來切圓角,方便快捷固翰。
UIImageView *userHeaderImgView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"header"]];
userHeaderImgView.layer.cornerRadius = 39;
userHeaderImgView.layer.masksToBounds = YES;
好處:方便快捷狼纬,2個屬性就能搞定 UIView 的圓角切割羹呵。
壞處:切的圓角會產(chǎn)生混合圖層,影響效率畸颅。尤其對于collectionView的cell上使用復用時担巩,會很影響幀數(shù)
。
第二種没炒,使用 CAShaperLayer 搭配 UIBezierPath 路徑設(shè)置切割路徑涛癌,然后把 layer 設(shè)置到 UIView 的 mask 屬性上。
UIImageView *userHeaderImgView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"header"]];
CAShapeLayer *cornerLayer = [CAShapeLayer layer];
UIBezierPath *cornerPath = [UIBezierPath bezierPathWithRoundedRect:userHeaderImgView.bounds cornerRadius:39];
cornerLayer.path = cornerPath.CGPath;
cornerLayer.frame = userHeaderImgView.bounds;
userHeaderImgView.layer.mask = cornerLayer;
好處:切割的圓角不會產(chǎn)生混合圖層送火,提高效率拳话,并且可以分別控制四個角的圓角。
壞處:代碼量偏多种吸, 該方式API都必須使用frame弃衍,所以對于使用使用約束布局的view就需要事先寫死高度。不方便坚俗。
實際運用
項目中有時常用到卡片風格镜盯,首尾cell需要分別切上圓角和下圓角,cell也幾乎是不定高度猖败。所以針對第二種方式封裝了適用于frame速缆,約束布局的cell,提供了像系統(tǒng)切圓角的api恩闻,并且能指定切割圓角艺糜。
原理:view在layoutSubviews方法中的frame確定了,所以在該方法中進行l(wèi)ayer的mask設(shè)置幢尚。通過runtime交換了方法破停,并且添加了相關(guān)的參數(shù)。
+ (void)load {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
Class targetClass = [self class];
SEL originalSelector = @selector(layoutSubviews);
SEL swizzledSelector = @selector(sy_layoutSubviews);
[self swizzleMethod:targetClass orgSel:originalSelector swizzSel:swizzledSelector];
});
}
- (void)sy_layoutSubviews {
[self sy_layoutSubviews];
if (self.xk_openClip) {
if (self.xk_clipType == XKCornerClipTypeNone) {
self.layer.mask = nil;
} else {
UIRectCorner rectCorner = [self getRectCorner];
if (self.maskLayer == nil) {
self.maskLayer = [[CAShapeLayer alloc] init];
}
UIBezierPath *maskPath;
maskPath = [UIBezierPath bezierPathWithRoundedRect:self.bounds byRoundingCorners:rectCorner cornerRadii:CGSizeMake(self.xk_radius, self.xk_radius)];
self.maskLayer.frame = self.bounds;
self.maskLayer.path = maskPath.CGPath;
self.layer.mask = self.maskLayer;
}
}
}
以下是詳細使用
self.view.backgroundColor = [UIColor whiteColor];
_frameView = [[UILabel alloc] init];
_frameView.backgroundColor = [UIColor redColor];
_frameView.text = @"frame";
_frameView.frame = CGRectMake(20, 100, 200, 100);
_frameView.xk_openClip = YES;
_frameView.xk_radius = 20;
_frameView.xk_clipType = XKCornerClipTypeTopRight|XKCornerClipTypeBottomLeft;
[self.view addSubview:_frameView];
_masonryView = [[UILabel alloc] init];
_masonryView.text = @"autoLayout";
_masonryView.xk_openClip = YES;
_masonryView.xk_radius = 20;
_masonryView.backgroundColor = [UIColor orangeColor];
_masonryView.xk_clipType = XKCornerClipTypeTopRight|XKCornerClipTypeTopLeft;
[self.view addSubview:_masonryView];
[_masonryView mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.equalTo(self.frameView.mas_bottom).offset(40);
make.left.equalTo(self.frameView);
make.size.mas_equalTo(CGSizeMake(100, 100));
}];
切圓角實例
2 切圓角場景下加邊框或者是加陰影
第一種 對于加邊框和加陰影的情況尉剩,不過不涉及指定切圓角真慢,那么可以使用
UIView *aa1 = [[UIView alloc] init];
[KEY_WINDOW addSubview:aa1];
aa1.backgroundColor = [UIColor redColor];
aa1.frame = CGRectMake(100, 300, 100, 50);
// 圓角
aa1.layer.cornerRadius = 10;
// 邊框
aa1.layer.borderColor = [UIColor orangeColor].CGColor;
aa1.layer.borderWidth = 5;
// 陰影
aa1.layer.shadowColor = [UIColor blackColor].CGColor;
aa1.layer.shadowOffset = CGSizeMake(2, 2);
aa1.layer.shadowRadius = 10;
aa1.layer.shadowOpacity = 0.5;
第二種, 同樣使用 CAShaperLayer 搭配 UIBezierPath 路徑實現(xiàn)理茎,不同的是不能設(shè)置在UIView.layer的mask屬性黑界,因為會導致陰影被切掉。使用addSublayer
原理同上交換方法功蜓。
- (void)sy_borderlayoutSubviews {
[self sy_borderlayoutSubviews];
if (self.xk_openBorder) {
// if (self.borderStatusChange == NO) return;
self.borderStatusChange = NO;
if (self.xk_openBorder == XKBorderTypeNone) {
[self.subBorderLayer removeFromSuperlayer];
} else {
UIRectCorner rectCorner = [self getRectCornerForBorder];
if (self.subBorderLayer == nil) {
self.subBorderLayer = [[CAShapeLayer alloc] init];
}
UIBezierPath *maskPath;
maskPath = [UIBezierPath bezierPathWithRoundedRect:CGRectMake(0, 0, self.width - self.xk_borderWidth, self.height - self.xk_borderWidth) byRoundingCorners:rectCorner cornerRadii:CGSizeMake(self.xk_borderRadius, self.xk_borderRadius)];
self.subBorderLayer.frame = CGRectMake(self.xk_borderWidth / 2, self.xk_borderWidth / 2,self.width - self.xk_borderWidth,self.height - self.xk_borderWidth);
self.subBorderLayer.path = maskPath.CGPath;
self.subBorderLayer.fillColor = self.xk_borderFillColor.CGColor;
self.subBorderLayer.strokeColor = self.xk_borderColor.CGColor;
self.subBorderLayer.lineWidth = self.xk_borderWidth;
if (!self.subBorderLayer.superlayer) {
[self.layer addSublayer:self.subBorderLayer];
}
}
}
}
使用
UIView *aa = [[UIView alloc] init];
[KEY_WINDOW addSubview:aa];
aa.frame = CGRectMake(20, 300, 100, 50);
aa.xk_openBorder = YES; // 開啟功能
aa.xk_borderFillColor = [UIColor redColor]; // 視圖背景顏色這樣設(shè)置
aa.xk_borderType = XKBorderTypeTopLeft; // 指定下方圓角
aa.xk_borderRadius = 20; // 圓角大小
aa.xk_borderColor = [UIColor orangeColor]; // 邊框顏色
aa.xk_borderWidth = 2; // 邊框?qū)挾? // 陰影還是系統(tǒng)的方法
aa.layer.shadowColor = [UIColor blackColor].CGColor;
aa.layer.shadowOffset = CGSizeMake(2, 2);
aa.layer.shadowRadius = 10;
aa.layer.shadowOpacity = 0.5;
效果
以上的方法通過組合基本可以應(yīng)對所有的情況了园爷。上述兩個分類在這里
https://github.com/sy5075391/XKCornerRadius
為了方便使用也可以使用pod安裝
Installation
pod 'XKCornerRadius'
Author
Jamesholy, 447523382@qq.com,http://www.reibang.com/u/2df38653a8d4