OC_靈活的切圓角工具(對(duì)UIView切圓角與陰影添加的優(yōu)化)

這個(gè)是PYKit的段代碼,點(diǎn)擊這里查看全部

ios 開(kāi)發(fā) 對(duì)于圓角的裁切,爭(zhēng)議很大,于是做了一個(gè)對(duì)比,對(duì)比過(guò)程下面會(huì)有詳細(xì)的解釋,得出結(jié)論為相同運(yùn)行環(huán)境下,用shapLayer 裁切與用maskToBounds裁切耗時(shí)比例大概為 **6 : 7**

工具的封裝:

以后你可能這樣切圓角

BaseFilletShadowView *view = [BaseFilletShadowView new];
  view
        .config
        .setUpCutRect(CGRectMake(0, 0, -1, -1))//裁切的位置及范圍 優(yōu)先級(jí)低于 cutRectEdgeWithSelf
        .setUpCutRectEdgeWithSelf(UIEdgeInsetsMake(20, 20, 20, 20))//裁切的位置及范圍
        .setUpRadius(10)//四個(gè)角切圓的圓形的半徑
        .setUpLeftTopAddRadius(10)//左上角追加圓角半徑
        .setUpLeftBottomAddRadius(10)//左下角追加圓角半徑
        .setUpRightTopAddRadius(10)//右上角追加圓角半徑
        .setUpRightBottomAddRadius(10);//右下角追加圓角半徑 
  1. 結(jié)構(gòu):內(nèi)部添加了一個(gè)負(fù)責(zé)陰影的shadowLayer 與一個(gè)負(fù)責(zé)圓形切圖的containerView,并且根據(jù)config屬性統(tǒng)一或分別設(shè)置各個(gè)角的弧度。
  2. 調(diào)用:config添加了鏈?zhǔn)秸{(diào)用方法。view 鏈?zhǔn)秸{(diào)用在這里

config .h


#import <UIKit/UIKit.h>

@interface BaseFilletShadowViewConfig : NSObject

/**裁切的位置及范圍*/
@property (nonatomic,assign) CGRect cutRect;
- (BaseFilletShadowViewConfig *(^)(CGRect cutRect)) setUpCutRect;

/**圓形的半徑*/
@property (nonatomic,assign) CGFloat radius;
- (BaseFilletShadowViewConfig *(^)(CGFloat radius)) setUpRadius;

/**四個(gè)角的半徑控制接口*/
@property (nonatomic,assign) CGFloat leftTopAddRadius;
- (BaseFilletShadowViewConfig *(^)(CGFloat leftTopAddRadius)) setUpLeftTopAddRadius;

@property (nonatomic,assign) CGFloat leftBottomAddRadius;
- (BaseFilletShadowViewConfig *(^)(CGFloat leftBottomAddRadius)) setUpLeftBottomAddRadius;

@property (nonatomic,assign) CGFloat rightTopAddRadius;
- (BaseFilletShadowViewConfig *(^)(CGFloat rightTopAddRadius)) setUpRightTopAddRadius;

@property (nonatomic,assign) CGFloat rightBottomAddRadius;
- (BaseFilletShadowViewConfig *(^)(CGFloat rightBottomAddRadius)) setUpRightBottonAddRadius;

///**圖片的透明度*/
//@property (nonatomic,assign) CGFloat alpha;
//- (BaseFilletShadowViewConfig *(^)(CGFloat alpha)) setUpAlpha;
@end

config .m

#import "BaseFilletShadowViewConfig.h"

@implementation BaseFilletShadowViewConfig
- (BaseFilletShadowViewConfig *(^)(CGRect cutRect)) setUpCutRect {
    return ^(CGRect cutRect) {
        self.cutRect = cutRect;
        return self;
    };
}
- (BaseFilletShadowViewConfig *(^)(CGFloat radius)) setUpRadius {
    return ^(CGFloat radius) {
        self.radius = radius;
        return self;
    };
}
- (BaseFilletShadowViewConfig *(^)(CGFloat leftTopRadius)) setUpLeftTopAddRadius  {
    return ^(CGFloat radius) {
        self.leftTopAddRadius = radius;
        return self;
    };
}
- (BaseFilletShadowViewConfig *(^)(CGFloat leftBottomRadius)) setUpLeftBottomAddRadius {
    return ^(CGFloat radius) {
        self.leftBottomAddRadius = radius;
        return self;
    };
}
- (BaseFilletShadowViewConfig *(^)(CGFloat rightTopRadius)) setUpRightTopAddRadius {
    return ^(CGFloat radius) {
        self.rightTopAddRadius = radius;
        return self;
    };
}
- (BaseFilletShadowViewConfig *(^)(CGFloat rightBottomRadius)) setUpRightBottonAddRadius {
    return ^(CGFloat radius) {
        self.rightBottomAddRadius = radius;
        return self;
    };
}
- (BaseFilletShadowViewConfig *(^)(CGFloat alpha)) setUpAlpha {
    return ^(CGFloat alpha) {
        self.alpha = alpha;
        return self;
    };
}
@end

BaseFilletShadowView.h


#import <UIKit/UIKit.h>
#import "BaseFilletShadowViewConfig.h"

/// 圓角陰影view
@interface BaseFilletShadowView : UIView
@property (nonatomic,strong) BaseFilletShadowViewConfig *config;

/**
 設(shè)置陰影必須要設(shè)置這個(gè)layer
 要保證這個(gè)layer 在最底層
 */
@property (nonatomic,strong) CALayer *shadowLayer;
/**
 在這個(gè)上邊布局,
 */
@property (nonatomic,strong) UIView *containerView;

/**
 開(kāi)始切圖
 */
- (void) reCut;

/**
 取消切圖
 */
- (void) unCunt;
@end

BaseFilletShadowView.m


#import "BaseFilletShadowView.h"
#import <Masonry/Masonry.h>
@interface BaseFilletShadowView ()
@property (nonatomic,strong) CAShapeLayer *shapeLayer;
@property (nonatomic,assign) BOOL isCut;
@property (nonatomic,assign) CGRect lastDrawFrame;

@end

@implementation BaseFilletShadowView

#pragma mark - init
- (instancetype)initWithFrame:(CGRect)frame {
    if (self = [super initWithFrame:frame]) {
        [self.layer addSublayer:self.shadowLayer];
        [self addSubview:self.containerView];
        [self.containerView mas_makeConstraints:^(MASConstraintMaker *make) {
            make.edges.equalTo(self);
        }];
    }
    return self;
}


#pragma mark - functions
- (void) unCunt {
    self.containerView.layer.mask = nil;
}

- (void) reCut {
    self.isCut = true;
    if (self.config.radius <= 0
        && self.config.leftTopAddRadius <= 0
        && self.config.leftBottomAddRadius <= 0
        && self.config.rightTopAddRadius <= 0
        && self.config.rightBottomAddRadius <= 0) {
        return;
    }
    self.containerView.layer.mask = self.shapeLayer;
    [self setupShapeLayerIfNeede];
}

- (void) setupShapeLayerIfNeede {
    if (CGSizeEqualToSize(self.frame.size, self.lastDrawFrame.size)) {
        return;
    }
    self.lastDrawFrame = self.frame;
    __weak typeof(self)weakSelf = self;
    [self createPathWithRect:self.config.cutRect andCallBack:^(CGMutablePathRef path) {
        weakSelf.shapeLayer.path = path;
        weakSelf.shadowLayer.shadowPath = path;
        
    }];
    [self setupShadowLayer];
}

- (void) setupShadowLayer {
    self.shadowLayer.backgroundColor = self.backgroundColor.CGColor;
    self.shadowLayer.frame = self.bounds;
}

//MARK: - 創(chuàng)建切圓路徑
- (void) createPathWithRect:(CGRect)rect andCallBack: (void(^)(CGMutablePathRef path))block {
    if (!block) return;
    CGMutablePathRef path = [self createMutablePathRefWithRect:rect];
    block(path);
    CFRelease(path);
}

- (CGMutablePathRef)createMutablePathRefWithRect:(CGRect)rect {
    
    CGRect cutRect = rect;
    CGFloat
    minx = CGRectGetMinX(cutRect),//矩形中最小的x
    midx = CGRectGetMidX(cutRect),//矩形中最大x值的一半
    maxx = CGRectGetMaxX(cutRect);//矩形中最大的x值
    
    CGFloat
    miny = CGRectGetMinY(cutRect),//矩形中最小的Y值
    midy = CGRectGetMidY(cutRect),//矩形中最大Y值的一半
    maxy = CGRectGetMaxY(cutRect);//矩形中最大的Y值
    
    CGFloat
    radius = self.config.radius;
    
    CGFloat
    leftTopRadiu = radius + self.config.leftTopAddRadius,
    rightTopRadiu = radius + self.config.rightTopAddRadius,
    leftBottomRadiu = radius + self.config.leftBottomAddRadius,
    rightBottomRadiu = radius + self.config.rightBottomAddRadius;
    
    CGMutablePathRef path = CGPathCreateMutable();
    CGPathMoveToPoint(path, nil, minx, midy);
    CGPathAddArcToPoint(path, nil, minx, miny, midx, miny, leftTopRadiu);
    CGPathAddArcToPoint(path, nil, maxx, miny, maxx, midy, rightTopRadiu);
    CGPathAddArcToPoint(path, nil, maxx, maxy, midx, maxy, rightBottomRadiu);
    CGPathAddArcToPoint(path, nil, minx, maxy, minx, midy, leftBottomRadiu);
    return path;
}

// MARK: properties get && set
- (BaseFilletShadowViewConfig *)config {
    if (!_config) {
        _config = [BaseFilletShadowViewConfig new];
        
        _config
        .setUpCutRect(self.bounds)
        .setUpRadius(0)
        .setUpAlpha(1);
    }
    return _config;
}
- (CAShapeLayer *)shapeLayer {
    if(!_shapeLayer) {
        _shapeLayer = [CAShapeLayer new];
    }
    return _shapeLayer;
}
- (UIView *)containerView {
    if (!_containerView) {
        _containerView = [UIView new];
    }
    return _containerView;
}
- (CALayer *)shadowLayer {
    if (!_shadowLayer) {
        _shadowLayer = [CALayer new];
    }
    return _shadowLayer;
}

- (void)layoutSubviews {
    [super layoutSubviews];
    self.shapeLayer.frame = self.bounds;
    self.shadowLayer.frame = self.bounds;
}
@end

優(yōu)化實(shí)驗(yàn)

以上是用 instrumentstime profiler 來(lái) 對(duì)運(yùn)行時(shí)間做的統(tǒng)計(jì)
過(guò)程。

  1. 自定義兩個(gè)tableView : PYMaskToBoundsTableViewPYRoundViewTableView
  2. 讓兩個(gè)tableView,除去 cellview 的裁切方式不同 外其他都一樣。
  3. 滾動(dòng)其中一個(gè),另外一個(gè)tableView 需要聯(lián)動(dòng)。
  4. 觀察tableViewcellForRow方法,比較耗時(shí)。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容

  • 1、通過(guò)CocoaPods安裝項(xiàng)目名稱項(xiàng)目信息 AFNetworking網(wǎng)絡(luò)請(qǐng)求組件 FMDB本地?cái)?shù)據(jù)庫(kù)組件 SD...
    陽(yáng)明AGI閱讀 16,003評(píng)論 3 119
  • 可能是快要臨近期中考試了,兒子最近的作業(yè)特別多,每天晚上都做到很晚。我都已經(jīng)熬不住,躺在沙發(fā)上打瞌睡了...
    慕敖閱讀 277評(píng)論 0 2
  • 轉(zhuǎn)眼間,畢業(yè)后的第三個(gè)春節(jié)馬上就要到了,2016年還剩下最后的27天,忽然之間感受到時(shí)間似乎過(guò)得越來(lái)越快了。 在這...
    LiarMaiq閱讀 185評(píng)論 0 0
  • 時(shí)間過(guò)得飛快啊,一眨眼就十年了,在商場(chǎng)的電梯里偶遇我的初戀情人,那種感覺(jué)特奇怪又別扭,你說(shuō)你當(dāng)初對(duì)著星星和月亮許下...
    可愛(ài)的小漫漫閱讀 396評(píng)論 0 1
  • 那是一個(gè)人秋天,深秋九月初一,而這天也是我的生日。一大早我就被廚房傳來(lái)的雜聲給吵醒,我暈乎乎的起了床,便去用...
    青空少年閱讀 128評(píng)論 0 0