搞开发这么久了,很少去看一些大神的代码.后悔啊.希望现在亡羊补牢,为时不晚!
这个是关于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 |
其他的没什么好说的,这里说一下visibleAlpha和viewController两个属性
- 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之类.使用过程中目前我也没发现什么问题.这个问题应该是不会存在了.
网友评论