美文网首页iOS 开发每天分享优质文章
OC_灵活的切圆角工具(对UIView切圆角与阴影添加的优化)

OC_灵活的切圆角工具(对UIView切圆角与阴影添加的优化)

作者: LiYaoPeng | 来源:发表于2018-11-15 16:49 被阅读134次

    这个是PYKit的段代码,点击这里查看全部

    ios 开发 对于圆角的裁切,争议很大,于是做了一个对比,对比过程下面会有详细的解释,得出结论为相同运行环境下,用shapLayer 裁切与用maskToBounds裁切耗时比例大概为 **6 : 7**

    工具的封装:

    以后你可能这样切圆角

    BaseFilletShadowView *view = [BaseFilletShadowView new];
      view
            .config
            .setUpCutRect(CGRectMake(0, 0, -1, -1))//裁切的位置及范围 优先级低于 cutRectEdgeWithSelf
            .setUpCutRectEdgeWithSelf(UIEdgeInsetsMake(20, 20, 20, 20))//裁切的位置及范围
            .setUpRadius(10)//四个角切圆的圆形的半径
            .setUpLeftTopAddRadius(10)//左上角追加圆角半径
            .setUpLeftBottomAddRadius(10)//左下角追加圆角半径
            .setUpRightTopAddRadius(10)//右上角追加圆角半径
            .setUpRightBottomAddRadius(10);//右下角追加圆角半径 
    
    1. 结构:内部添加了一个负责阴影的shadowLayer 与一个负责圆形切图的containerView,并且根据config属性统一或分别设置各个角的弧度。
    2. 调用:config添加了链式调用方法。view 链式调用在这里

    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;
    
    /**四个角的半径控制接口*/
    @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;
    
    /**
     设置阴影必须要设置这个layer
     要保证这个layer 在最底层
     */
    @property (nonatomic,strong) CALayer *shadowLayer;
    /**
     在这个上边布局,
     */
    @property (nonatomic,strong) UIView *containerView;
    
    /**
     开始切图
     */
    - (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: - 创建切圆路径
    - (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
    

    优化实验

    以上是用 instrumentstime profiler 来 对运行时间做的统计
    过程。

    1. 自定义两个tableView : PYMaskToBoundsTableViewPYRoundViewTableView
    2. 让两个tableView,除去 cellview 的裁切方式不同 外其他都一样。
    3. 滚动其中一个,另外一个tableView 需要联动。
    4. 观察tableViewcellForRow方法,比较耗时。

    相关文章

      网友评论

        本文标题:OC_灵活的切圆角工具(对UIView切圆角与阴影添加的优化)

        本文链接:https://www.haomeiwen.com/subject/ncpyfqtx.html