layoutIfNeeded 可能的实现机制
1 2 3 4 5 6 7 8 9 10
|
-(void)layoutIfNeeded { if (self._needsLayout) { UIView *sv = self.superview; if (sv._needsLayout) { [sv layoutIfNeeded]; } else { [self layoutSubviews]; } } }
|
其中 _needsLayout 由 setNeedsLayout 进行设置。
使用示例
现在自定义一个 UICustomView 继承自 UIView, 这个 UICustomView 中包含一个 contentView 属性和一个 edgeInsets 属性来控制contentView 的 frame。
这个自定义的 UICustomView 如下:
1 2 3 4 5 6
|
#import <UIKit/UIKit.h>
@interface UICustomView : UIView @property (nonatomic, strong) UIView * contentView; @property (nonatomic, assign) UIEdgeInsets edgeInsets; @end
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
|
#import "UICustomView.h"
@implementation UICustomView
- (instancetype)initWithFrame:(CGRect)frame{ self = [super initWithFrame:frame]; if (self) { _contentView = [[UIView alloc] initWithFrame:self.bounds]; [self addSubview:_contentView]; } return self; }
- (void)layoutSubviews{ [super layoutSubviews]; self.contentView.frame = CGRectMake( self.bounds.origin.x + self.edgeInsets.left, self.bounds.origin.y + self.edgeInsets.top, self.bounds.size.width - self.edgeInsets.left - self.edgeInsets.right, self.bounds.size.height - self.edgeInsets.top - self.edgeInsets.bottom); NSLog(@"调用===layoutSubviews %@",self); }
- (void)setEdgeInsets:(UIEdgeInsets)edgeInsets{ _edgeInsets = edgeInsets; [self setNeedsLayout]; [self layoutIfNeeded]; }
|
上面的 UICustomView 重写了 layoutSubViews 方法,并且实现了当 edgeInsets 的值发生改变,contentView 的 frame 随及发生改变。
当执行下面的动画:
1 2 3
|
[UIView animateWithDuration:2 animations:^{ self.edgeInsets = UIEdgeInsetsMake(45, 17, 18, 34); }];
|
contentView 动态变小,如果 setEdgeInsets: 方法中不调用 layoutIfNeeded,那么 contentView 的变小不会在 animate 的 block 中,而是在 block 外,也就动态变小。如果 setEdgeInsets: 方法中 只调用 layoutIfNeeded,那么 contentView 的大小不会改变,因为此时 setNeedsLayout 并没有标记。
参考:What is the relationship between UIView’s setNeedsLayout, layoutIfNeeded and layoutSubviews?
近期评论