避免不必要的布局计算
- 减少动态更新频率:
尽量减少频繁更改视图约束或框架的操作。如果必须进行动态更新,尝试批量处理这些更改,而不是每次小变化都触发布局更新。
例如,假设我们有一个视图
myView
,在一个循环中多次更改其约束:
// 不推荐,每次更改都会触发布局更新
for (int i = 0; i < 10; i++) {
NSLayoutConstraint *constraint = [NSLayoutConstraint constraintWithItem:myView attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1.0 constant:i * 10];
[myView addConstraint:constraint];
}
// 推荐,批量更新
[myView setTranslatesAutoresizingMaskIntoConstraints:NO];
NSMutableArray *constraints = [NSMutableArray array];
for (int i = 0; i < 10; i++) {
NSLayoutConstraint *constraint = [NSLayoutConstraint constraintWithItem:myView attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1.0 constant:i * 10];
[constraints addObject:constraint];
}
[myView addConstraints:constraints];
- 使用
layoutIfNeeded
时机:
仅在确实需要立即更新布局时调用 layoutIfNeeded
。通常,系统会在合适的时机自动调用布局更新,不必要的调用会浪费性能。
例如,假设在视图加载后我们想执行一些初始化布局调整:
- (void)viewDidLoad {
[super viewDidLoad];
// 执行一些视图初始化和约束添加
// 不要在这里立即调用 layoutIfNeeded,除非有特殊需求
}
// 当有明确的用户交互或其他操作需要立即更新布局时
- (IBAction)buttonTapped:(id)sender {
// 更改约束
NSLayoutConstraint *newConstraint = [NSLayoutConstraint constraintWithItem:self.someView attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeCenterX multiplier:1.0 constant:0];
[self.someView addConstraint:newConstraint];
[self.view layoutIfNeeded]; // 此时调用 layoutIfNeeded 以立即更新布局
}
- 延迟加载视图:
对于一些不马上需要显示的嵌套视图,延迟它们的加载和布局计算。可以使用
UIViewController
的 loadViewIfNeeded
按需加载视图。
例如,在一个 UIViewController
子类中:
@interface MyViewController : UIViewController
@property (nonatomic, strong) UIView *lazyLoadedView;
@end
@implementation MyViewController
- (UIView *)lazyLoadedView {
if (!_lazyLoadedView) {
_lazyLoadedView = [[UIView alloc] init];
// 添加约束等操作
_lazyLoadedView.translatesAutoresizingMaskIntoConstraints = NO;
[self.view addSubview:_lazyLoadedView];
NSLayoutConstraint *leadingConstraint = [NSLayoutConstraint constraintWithItem:_lazyLoadedView attribute:NSLayoutAttributeLeading relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeLeading multiplier:1.0 constant:10];
NSLayoutConstraint *topConstraint = [NSLayoutConstraint constraintWithItem:_lazyLoadedView attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeTop multiplier:1.0 constant:10];
[self.view addConstraints:@[leadingConstraint, topConstraint]];
}
return _lazyLoadedView;
}
- (void)someActionThatNeedsLazyView {
[self.lazyLoadedView loadViewIfNeeded];
// 对 lazyLoadedView 进行操作
}
@end
合理设置约束
- 保持约束简洁:
避免过度复杂或冗余的约束。例如,不要同时设置水平和垂直方向的固定尺寸以及与父视图的边缘约束,这样可能会导致约束冲突或不必要的计算。
// 不推荐,冗余约束
UIView *view = [[UIView alloc] init];
[view setTranslatesAutoresizingMaskIntoConstraints:NO];
[superview addSubview:view];
NSLayoutConstraint *widthConstraint = [NSLayoutConstraint constraintWithItem:view attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1.0 constant:200];
NSLayoutConstraint *heightConstraint = [NSLayoutConstraint constraintWithItem:view attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1.0 constant:100];
NSLayoutConstraint *leadingConstraint = [NSLayoutConstraint constraintWithItem:view attribute:NSLayoutAttributeLeading relatedBy:NSLayoutRelationEqual toItem:superview attribute:NSLayoutAttributeLeading multiplier:1.0 constant:10];
NSLayoutConstraint *topConstraint = [NSLayoutConstraint constraintWithItem:view attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:superview attribute:NSLayoutAttributeTop multiplier:1.0 constant:10];
[superview addConstraints:@[widthConstraint, heightConstraint, leadingConstraint, topConstraint]];
// 推荐,更简洁的方式
UIView *view = [[UIView alloc] init];
[view setTranslatesAutoresizingMaskIntoConstraints:NO];
[superview addSubview:view];
NSLayoutConstraint *leadingConstraint = [NSLayoutConstraint constraintWithItem:view attribute:NSLayoutAttributeLeading relatedBy:NSLayoutRelationEqual toItem:superview attribute:NSLayoutAttributeLeading multiplier:1.0 constant:10];
NSLayoutConstraint *topConstraint = [NSLayoutConstraint constraintWithItem:view attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:superview attribute:NSLayoutAttributeTop multiplier:1.0 constant:10];
NSLayoutConstraint *trailingConstraint = [NSLayoutConstraint constraintWithItem:view attribute:NSLayoutAttributeTrailing relatedBy:NSLayoutRelationEqual toItem:superview attribute:NSLayoutAttributeTrailing multiplier:1.0 constant:-10];
NSLayoutConstraint *bottomConstraint = [NSLayoutConstraint constraintWithItem:view attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:superview attribute:NSLayoutAttributeBottom multiplier:1.0 constant:-10];
[superview addConstraints:@[leadingConstraint, topConstraint, trailingConstraint, bottomConstraint]];
- 使用优先级:
合理设置约束优先级,确保在约束冲突时,重要的约束能够优先满足。例如,在一个包含标题和描述的视图中,标题可能更重要,应优先保持其布局。
UIView *titleView = [[UIView alloc] init];
UIView *descriptionView = [[UIView alloc] init];
[titleView setTranslatesAutoresizingMaskIntoConstraints = NO];
[descriptionView setTranslatesAutoresizingMaskIntoConstraints = NO];
[superview addSubviews:@[titleView, descriptionView]];
NSLayoutConstraint *titleLeadingConstraint = [NSLayoutConstraint constraintWithItem:titleView attribute:NSLayoutAttributeLeading relatedBy:NSLayoutRelationEqual toItem:superview attribute:NSLayoutAttributeLeading multiplier:1.0 constant:10];
NSLayoutConstraint *titleTopConstraint = [NSLayoutConstraint constraintWithItem:titleView attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:superview attribute:NSLayoutAttributeTop multiplier:1.0 constant:10];
NSLayoutConstraint *descriptionTopConstraint = [NSLayoutConstraint constraintWithItem:descriptionView attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:titleView attribute:NSLayoutAttributeBottom multiplier:1.0 constant:10];
NSLayoutConstraint *descriptionLeadingConstraint = [NSLayoutConstraint constraintWithItem:descriptionView attribute:NSLayoutAttributeLeading relatedBy:NSLayoutRelationEqual toItem:superview attribute:NSLayoutAttributeLeading multiplier:1.0 constant:10];
// 设置标题约束优先级更高
titleLeadingConstraint.priority = UILayoutPriorityRequired;
titleTopConstraint.priority = UILayoutPriorityRequired;
[superview addConstraints:@[titleLeadingConstraint, titleTopConstraint, descriptionTopConstraint, descriptionLeadingConstraint]];
- 避免跨层级复杂约束:
尽量避免在深度嵌套的视图之间设置直接约束。如果可能,通过中间视图或容器视图来传递布局信息。
例如,有一个
A
视图包含 B
视图,B
视图又包含 C
视图,不建议直接从 A
到 C
设置约束:
// 不推荐
UIView *viewA = [[UIView alloc] init];
UIView *viewB = [[UIView alloc] init];
UIView *viewC = [[UIView alloc] init];
[viewA setTranslatesAutoresizingMaskIntoConstraints = NO];
[viewB setTranslatesAutoresizingMaskIntoConstraints = NO];
[viewC setTranslatesAutoresizingMaskIntoConstraints = NO];
[viewA addSubview:viewB];
[viewB addSubview:viewC];
// 直接从 A 到 C 设置约束
NSLayoutConstraint *badConstraint = [NSLayoutConstraint constraintWithItem:viewC attribute:NSLayoutAttributeLeading relatedBy:NSLayoutRelationEqual toItem:viewA attribute:NSLayoutAttributeLeading multiplier:1.0 constant:10];
[viewA addConstraint:badConstraint];
// 推荐,通过 B 来传递布局信息
NSLayoutConstraint *bLeadingConstraint = [NSLayoutConstraint constraintWithItem:viewB attribute:NSLayoutAttributeLeading relatedBy:NSLayoutRelationEqual toItem:viewA attribute:NSLayoutAttributeLeading multiplier:1.0 constant:10];
NSLayoutConstraint *cLeadingConstraint = [NSLayoutConstraint constraintWithItem:viewC attribute:NSLayoutAttributeLeading relatedBy:NSLayoutRelationEqual toItem:viewB attribute:NSLayoutAttributeLeading multiplier:1.0 constant:10];
[viewA addConstraint:bLeadingConstraint];
[viewB addConstraint:cLeadingConstraint];