美文网首页
YYKit框架学习之YYCategory -- UIView+

YYKit框架学习之YYCategory -- UIView+

作者: 番茄炒西红柿啊 | 来源:发表于2019-05-21 17:11 被阅读0次

    搞开发这么久了,很少去看一些大神的代码.后悔啊.希望现在亡羊补牢,为时不晚!

    这个是关于UIView的扩展

    作者官方文档


    属性篇:

    属性名 解释
    bottom frame.origin.y + frame.size.height
    centerX center.x
    centerY center.y
    height frame.size.height
    left frame.origin.x
    origin frame.origin
    right frame.origin.x + frame.size.width
    size frame.size
    top frame.origin.y
    viewController 获取当前view所处的视图控制器 (下文有详解)
    visibleAlpha 返回屏幕上的可见alpha,考虑superview和window (下文有详解)
    width frame.size.width

    其他的没什么好说的,这里说一下visibleAlphaviewController两个属性

    • viewController这个属性其实就是通过一层一层的遍历nextResponder,直到找到是UIViewController类型为止.这里涉及到"响应链"方面的知识点.
    • visibleAlpha 其实看字面解释没太弄懂意思,你可以看下作者的源码实现.源码逻辑不涉及到任何技术点,会OC语法你就能看懂.源码如下:
    - (CGFloat)visibleAlpha {
        if ([self isKindOfClass:[UIWindow class]]) {
            if (self.hidden) return 0;
            return self.alpha;
        }
        if (!self.window) return 0;
        CGFloat alpha = 1;
        UIView *v = self;
        while (v) {
            if (v.hidden) {
                alpha = 0;
                break;
            }
            alpha *= v.alpha;
            v = v.superview;
        }
        return alpha;
    }
    
    • 看完源码能够弄懂其中含义了(可视透明度,UIView 遍历到最后的根都是UIWindow
      这里用了透明度的累积), 应该是我比较菜吧,暂时不知道visibleAlpha的此段实现逻辑会在什么情况会用到.

    方法篇:

    方法名 类型 解释
    - (CGPoint)convertPoint:(CGPoint)point toViewOrWindow:(nullable UIView *)view 实例方法 将基于调用者坐标系的point转换成基于view坐标系的point
    - (CGRect)convertRect:(CGRect)rect fromViewOrWindow:(nullable UIView *)view 同上 将基于view坐标系的rect转换成相对于调用者坐标系的rect
    - (CGRect)convertRect:(CGRect)rect toViewOrWindow:(nullable UIView *)view 同上 将基于调用者坐标系的rect转换成相对于view坐标系的rect
    - (void)removeAllSubviews 同上 移除调用者所有的子视图
    - (void)setLayerShadow:(nullable UIColor *)color offset:(CGSize)offset radius:(CGFloat)radius 同上 设置shadow, 颜色, 偏移, 圆角
    - (nullable UIImage *)snapshotImage 同上 截图
    - (nullable UIImage *)snapshotImageAfterScreenUpdates:(BOOL)afterUpdates 同上 截图 It’s faster than “snapshotImage”
    - (nullable NSData *)snapshotPDF 同上 转换成pdf

    详解

    0E630441BD796968AF14DF9AF653C95A.png

    如图:

    • 橙色的view,我们取名为orangeView(20, 80, 335, 200), orangeView添加在self.view上,(self是当前ViewController).
    • 黄色的view,我们取名为yellowView(10, 10, 30, 30), yellowView添加在orrangeView上.
        CGRect rect = [orangeView convertRect:CGRectMake(0, 0, 1, 1) fromViewOrWindow:self.view];
        NSLog(@"%@", NSStringFromCGRect(rect));
        // 输出为  {{-20, -80}, {1, 1}}
        
        CGPoint point = [orangeView convertPoint:CGPointMake(0, 0) fromViewOrWindow:self.view];
        NSLog(@"%@", NSStringFromCGPoint(point));
        // 输出为 {-20, -80}
        
        point = [orangeView convertPoint:CGPointMake(1, 1) toViewOrWindow:self.view];
        NSLog(@"%@", NSStringFromCGPoint(point));
        // 输出为 {21, 81}
    

    -(void)setLayerShadow:(nullable UIColor *)color offset:(CGSize)offset radius:(CGFloat)radius

    这个设置阴影没什么好说的,不过阅读源码的时候发现了2句我之前没有用过的属性

    self.layer.shouldRasterize = YES;
    self.layer.rasterizationScale = [UIScreen mainScreen].scale;
    

    解释:

    光栅化
    《iOS 开发中的离屏渲染问题》中提到的 GPU 离屏渲染是自动触发的,而开启光栅化,是手动启动离屏渲染,并且将离屏渲染的工作交由 CPU 处理。

    开启光栅化会将图层渲染为一个屏幕之外的位图(bitmap),然后将这个位图缓存起来。图层有复杂的视觉效果,这样做就会比重绘所有帧划划算的多。但是光栅化原始图像需要时间,而且还会消耗额外的内存。

    当我们使用得当,光栅化可以提供很大的性能优势,但是一定要避免用在内容是动态变化的图层上,不然它缓存方面的优势就会丧失,而且会让性能变的更糟另外要注意的一点,设置 shouldRasterize 的同时也要设置 rasterizationScale。

    上文解释中加粗的部分请额外注意.

    额外补充:
    最优设置
    在《iOS 性能优化之视图圆角》中提到了几种性能优化的方法,开启光栅化也能起到一定的性能优化作用。

    经过测试,对于 tableView 来说,光栅化性能最好的方式是是开启 cell 的 shouldRasterize,并将 rasterizationScale 设置为 UIScreen.main.scale。如果设置cell.layer.rasterizationScale = cell.layer.contentsScale则会出现视图模糊的现象。

    cell.layer.shouldRasterize = true
    cell.layer.rasterizationScale = UIScreen.main.scale
    若 cell 中有多个需要离屏渲染的子视图,对每个子视图分别开启光栅化并不会优化性能,反而可能造成性能下降。

    参考文献

    关于截屏- (nullable UIImage *)snapshotImageAfterScreenUpdates:(BOOL)afterUpdates

    afterUpdates参数为YES,代表视图的属性改变渲染完毕后截屏,参数为NO代表立刻将当前状态的视图截图

    光看理论云里雾里? ok,我们直接撸代码(上方为视图view,下方为view的截图,点击开关的时候开始调用截图方法):

    • afterUpdates = NO


      图二.gif


    • afterUpdates = YES;


      图3.gif



    看完上面的演示,原理一目了然.

    写在最后

    看到网上有部分较老的文章有提到UIView+YYAdd这个扩展和Masonry有冲突.什么self.left之类的使用失效问题.不过我看了最新的Masonry源码都加了前缀,现在都是mas_left之类.使用过程中目前我也没发现什么问题.这个问题应该是不会存在了.

    相关文章

      网友评论

          本文标题:YYKit框架学习之YYCategory -- UIView+

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