在 AutoLayout 中使用 CALayer
2018-11-06 本文已影响20人
AprSnow
使用 AutoLayout
时,view
不会立刻布局,而如果此时恰好需要给 view
添加 layer
,layer
的 frame
设置为 view
的 frame
会得到 (0, 0)
,那么如果在 AutoLayout
中设置 CALayer
的 frame
呢?
方法一
通过重写 UIView
的 + (Class)layerClass
方法,自定义 CALayer
。
@implementation PlayerView
+ (Class)layerClass {
return [AVPlayerLayer class];
}
@end
在实际中用的时候就可以直接添加
playerView = [PlayerView new];
AVPlayer *player = [[AVPlayer alloc] initWithPlayerItem:playItem];
[(AVPlayerLayer *)playerView.layer setPlayer:player];
方法二
通过 block
回调 UIView
的 layoutSubviews
,这样就可以很灵活的布局 CALayer
了。
@implementation UIView (LayoutSubviewsCallback)
+ (void)load {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
Method originalMethod = class_getInstanceMethod(self,
@selector(layoutSubviews));
Method newMethod = class_getInstanceMethod(self,
@selector(ls_layoutSubviews));
BOOL didAddMethod = class_addMethod(self,
@selector(layoutSubviews),
method_getImplementation(newMethod),
method_getTypeEncoding(newMethod));
if (didAddMethod) {
class_replaceMethod(self,
@selector(ls_layoutSubviews),
method_getImplementation(originalMethod),
method_getTypeEncoding(originalMethod));
} else {
method_exchangeImplementations(originalMethod, newMethod);
}
});
}
- (void)ls_layoutSubviews {
[self ls_layoutSubviews];
if (self.layoutSubviewsCallback) {
self.layoutSubviewsCallback(self);
}
}
- (void)setLayoutSubviewsCallback:(void (^)(UIView *))layoutSubviewsCallback {
objc_setAssociatedObject(self,
"layoutSubviewsCallback",
layoutSubviewsCallback,
OBJC_ASSOCIATION_RETAIN);
}
- (void (^)(UIView *))layoutSubviewsCallback {
return objc_getAssociatedObject(self, "layoutSubviewsCallback");
}
@end
使用时:
AVPlayerLayer *avLayer = [AVPlayerLayer new];
[playerView.layer addSublayer:avLayer];
playerView.layoutSubviewsCallback = ^(UIView *view) {
avLayer.frame = view.bounds;
};
方法三
直接在 viewDidLayoutSubviews
中设置
- (void)viewDidLayoutSubviews {
[super viewDidLayoutSubviews];
avLayer.frame = playerView.frame;
}
方法四
使用 GCD
,因为即使设置延迟 0
秒,GCD
的执行也会在下一个 runloop
,此时 view
已经布局结束。
dispatch_after(dispatch_time(DISPATCH_TIME_NOW,
(int64_t)(0 * NSEC_PER_SEC)),
dispatch_get_main_queue(), ^{
avLayer.frame = playerView.frame;
});