I have come to appreciate the work that Auto Layout does for me, but I'm with Brent Simmons on the topic of not using Interface Builder to set up the constraints. The interface as provided by Apple is flexible but extremely verbose — clearly designed for code generator instead of human use. For me it exemplifies the worst of Objective-C with repeating overlong identical prefixes and rarely used parameters obfuscating all meaning instead of providing clarity to the code. I've seen Florian Kugler's FLKAutoLayout that hides the constraint creation in category on UIView
.
Are there other ways to make the layout constraints in code cleaner and easier to understand?
I tried to stay as close as possible to the Apple's implementation, acknowledging the existence of NSLayoutConstraint
, so I have simply defined a set of Concise Auto Layout macros that remove the prefixes from attributes and relations and wrap the constraint creation in a constructor function-like macros (also omitting the multiplier parameter that I never use):
Constraint
ConstantConstraint
VisualConstraints
VisualConstraintWithMetrics
To attach multiple simple constraints to view, I wrap them in array literal. I always prefix non-zero constants with a sign, to emphasize the displacement. In practice it looks like this (instance variables reffer to views):
[self.view addConstraints:
@[Constraint(_verticalSeparator, CenterX, Equal, _top, CenterX, 0),
Constraint(_verticalSeparator, CenterY, Equal, _top, CenterY, +22),
Constraint(_verticalSeparator, Height, Equal, _localWeather, Height, 0),
Constraint(_localWeather, CenterY, Equal, _verticalSeparator, CenterY, 0),
Constraint(_addLocation, CenterY, Equal, _verticalSeparator, CenterY, 0),
Constraint(_touchDown, Trailing, Equal, _verticalSeparator, Trailing, -1),
Constraint(_touchDown, CenterY, Equal, _localWeather, CenterY, 0),
Constraint(_touchDown, Width, Equal, _localWeather, Width, +26),
Constraint(_touchDown, Height, Equal, _localWeather, Height, 0)
]];
id f = @"[_localWeather]-space-[_verticalSeparator]-space-[_addLocation]";
[self.view addConstraints:
VisualConstraintWithMetrics(f, @{@"space": @11},
_localWeather, _verticalSeparator, _addLocation)];
[_tableCell addConstraint:ConstantConstraint(_tableCell, Height, Equal, 44)];
When dealing with group of views that all share the same setup, I enumerate over array literal like this:
[@[_top, _middle, _bottom, _touchDown, _verticalSeparator]
enumerateObjectsUsingBlock:^(UIView *view, NSUInteger idx, BOOL *stop) {
view.translatesAutoresizingMaskIntoConstraints = NO;
[self.view addSubview:view];
}];
Filling the superview
horizontally happened often enough, that its lifted into its own macro:
[@[_top, _middle, _bottom] enumerateObjectsUsingBlock:horizontallyFillSuperview];
I'll update this answer as my style evolves…
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With