iOS自定义视图约束添加:layoutSubviews与updateConstraints使用时机及正确性验证
Hey there! Let's clear up the confusion around layoutSubviews and updateConstraints in iOS development, and fix your current implementation.
layoutSubviews vs updateConstraints First, let's break down the core purpose of each method—they serve very different roles in the layout pipeline.
updateConstraints
This is the dedicated place for managing Auto Layout constraints. The system calls it when constraints need to be recalculated (usually after you call setNeedsUpdateConstraints).
- Do: Add, modify, or remove constraints here. Only make changes when the actual constraint values need to update (e.g., a dynamic height based on content).
- Don't: Adjust view frames, perform layout calculations, or do anything unrelated to constraints.
- Critical note: Always call
[super updateConstraints]at the end of your implementation. Also, avoid adding duplicate constraints—wrap dynamic changes in checks to ensure you only modify what's necessary.
layoutSubviews
This is the final layout execution phase. The system triggers it when the view's frame/bounds changes, or after you call setNeedsLayout.
- Do: Use this for frame-based layout (if you're not using Auto Layout), or for post-layout tasks that depend on the final frame of subviews (e.g., adjusting a layer's corner radius or shadow path to match a view's new bounds).
- Don't: Add or modify Auto Layout constraints here. Every time
layoutSubviewsruns, you'd be adding duplicate constraints, leading to conflicts, performance hits, and broken layouts.
Is Your Current Implementation Correct?
Short answer: No, and here's why:
- Every time
layoutSubviewsruns (which happens frequently—on rotation, parent view size changes, etc.), you're adding new constraints. This quickly creates duplicate constraints, causing layout conflicts and console warnings. - You're using
layoutSubviewsfor a task it's not designed for—constraint management violates Auto Layout's intended workflow.
How to Fix Your Implementation
Let's adjust your approach to align with best practices:
1. Add Fixed Constraints During Initialization
You don't need to wait for the view's frame to be set to add most constraints! Auto Layout calculates frames automatically based on parent view size and constraint rules.
- (instancetype)initWithFrame:(CGRect)frame { self = [super initWithFrame:frame]; if (self) { [self setupSubviews]; [self setupBaseConstraints]; } return self; } - (instancetype)initWithCoder:(NSCoder *)coder { self = [super initWithCoder:coder]; if (self) { [self setupSubviews]; [self setupBaseConstraints]; } return self; } - (void)setupSubviews { // Create and add your subviews here UIView *customSubview = [[UIView alloc] init]; customSubview.translatesAutoresizingMaskIntoConstraints = NO; [self addSubview:customSubview]; self.subview = customSubview; } - (void)setupBaseConstraints { // Add fixed constraints (e.g., pin to parent edges with padding) [NSLayoutConstraint activateConstraints:@[ self.subview.topAnchor.constraintEqualToAnchor:self.topAnchor constant:16, self.subview.leadingAnchor.constraintEqualToAnchor:self.leadingAnchor constant:16, self.subview.trailingAnchor.constraintEqualToAnchor:self.trailingAnchor constant:-16, self.subview.heightAnchor.constraintEqualToConstant:80 ]]; }
2. Update Dynamic Constraints in updateConstraints
If you need to adjust constraints later (e.g., based on a state change), do it in updateConstraints:
// First, store a reference to the dynamic constraint in your setup - (void)setupBaseConstraints { self.subviewHeightConstraint = self.subview.heightAnchor.constraintEqualToConstant:80; [NSLayoutConstraint activateConstraints:@[ // ... other constraints ... self.subviewHeightConstraint ]]; } - (void)updateConstraints { // Update the constraint only if needed if (self.shouldExpandSubview) { self.subviewHeightConstraint.constant = 160; } else { self.subviewHeightConstraint.constant = 80; } // Always call super last [super updateConstraints]; }
When you need to trigger this update, call [self setNeedsUpdateConstraints]—the system will handle calling updateConstraints and triggering layout.
3. Handle Adding/Removing Subviews Correctly
When you add or remove a subview, add its constraints immediately after adding it to the view hierarchy:
- (void)addNewSubview:(UIView *)newSubview { newSubview.translatesAutoresizingMaskIntoConstraints = NO; [self addSubview:newSubview]; // Add constraints right away [NSLayoutConstraint activateConstraints:@[ newSubview.centerXAnchor.constraintEqualToAnchor:self.centerXAnchor, newSubview.centerYAnchor.constraintEqualToAnchor:self.centerYAnchor, newSubview.widthAnchor.constraintEqualToConstant:100, newSubview.heightAnchor.constraintEqualToConstant:100 ]]; // If you need the layout to apply immediately (not wait for the next runloop) [self layoutIfNeeded]; }
Avoid calling setNeedsLayout unless you just need to mark the view for layout later—layoutIfNeeded forces immediate layout if needed.
Quick Recap
- Use
updateConstraintsonly for managing Auto Layout constraints (add/modify/remove). - Use
layoutSubviewsfor frame-based layout or post-layout tasks that depend on final view bounds. - Never add constraints in
layoutSubviews—it causes duplicates and conflicts. - Add constraints for new subviews immediately when they're added to the hierarchy.
内容的提问来源于stack exchange,提问作者Davis Mariotti

