How to deal with the verbosity of NSLayoutConstraint in code?

I came to understand the work that AutoMarket is for me, but I'm with Brent Simmons on the topic of not using Interface Builder to set limits. The interface provided by Apple is flexible but extremely detailed - explicitly designed for a code generator instead of human use. For me, this illustrates the worst of Objective-C with repeating overlay identical prefixes and rarely used parameters, confusing all values, rather than ensuring code clarity. I saw Florian Cugler's FLKAutoLayout , which hides the creation of a category restriction on a UIView .

Are there other ways to make layout restrictions in pure code more understandable?

+4
source share
3 answers

I tried to get as close as possible to Apple's implementation, recognizing the existence of NSLayoutConstraint , so I just defined a set of Compressed Auto Layout Macros that remove prefixes from attributes and relationships and complete the creation of constraints in the macro sequence of the constructor functions (also omitting the multiplier parameter that I never use) :

  • Constraint
  • ConstantConstraint
  • VisualConstraints
  • VisualConstraintWithMetrics

To make some simple restrictions on viewing, I end them in an array literal. I always prefix non-zero constants with a sign to emphasize the offset. In practice, it looks like this (instance variables refer 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 working with a group of views in which everyone has the same setting, I list the array literal as follows:

 [@[_top, _middle, _bottom, _touchDown, _verticalSeparator] enumerateObjectsUsingBlock:^(UIView *view, NSUInteger idx, BOOL *stop) { view.translatesAutoresizingMaskIntoConstraints = NO; [self.view addSubview:view]; }]; 

Filling a superview horizontally happened often enough to be lifted into its own macro:

 [@[_top, _middle, _bottom] enumerateObjectsUsingBlock:horizontallyFillSuperview]; 

I will update this answer when my style evolves ...

+1
source

Masonry Jonas Budelmann is a DSL for automatic layout that is much more readable than manually created layout lines and layout constraints. Via iOS Dev Weekly .

 UIEdgeInsets padding = UIEdgeInsetsMake(10, 10, 10, 10); [view1 mas_makeConstraints:^(MASConstraintMaker *make) { make.top.equalTo(superview.mas_top).with.offset(padding.top); make.left.equalTo(superview.mas_left).with.offset(padding.left); make.bottom.equalTo(superview.mas_bottom).with.offset(-padding.bottom); make.right.equalTo(superview.mas_right).with.offset(-padding.right); }]; 

It also has composite limitations for setting edges, size, and center:

 // make top, left, bottom, right equal view2 make.edges.equalTo(view2); // make top = superview.top + 5, left = superview.left + 10, // bottom = superview.bottom - 15, right = superview.right - 20 make.edges.equalTo(superview).insets(UIEdgeInsetsMake(5, 10, 15, 20)) // make width and height greater than or equal to titleLabel make.size.greaterThanOrEqualTo(titleLabel) // make width = superview.width + 100, height = superview.height - 50 make.size.equalTo(superview).sizeOffset(CGSizeMake(100, -50)) // make centerX and centerY = button1 make.center.equalTo(button1) // make centerX = superview.centerX - 5, centerY = superview.centerY + 10 make.center.equalTo(superview).centerOffset(CGPointMake(-5, 10)) 
+9
source

You can also use Parus lib to indicate your limitations. The main idea of ​​this library is to not distinguish yourself from NSLayoutConstraint and to allow you to work with restrictions as you see fit.

For instance:

 [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)]; 

will look like this:

 [self.view addConstraints PVGroup(@[ PVCenterXOf(_verticalSeparator).equalTo.centerXOf(_top), PVCenterYOf(_verticalSeparator).equalTo.centerYOf(_top).plus(22), PVHeightOf(_verticalSeparator).equalTo.heightOf(_localWeather), PVCenterYOf(_localWeather).equalTo.centerYOf(_verticalSeparator), PVCenterYOf(_addLocation).equalTo.centerYOf(_verticalSeparator), PVTrailingOf(_touchDown).equalTo.trailingOf(_verticalSeparator).minus(1), PVCenterYOf(_touchDown).equalTo.centerYOf(_localWeather), PVWidthOf(_touchDown).equalTo.widthOf(_localWeather).plus(26), PVHightOf(_touchDown).equalTo.heightOf(_localWeather), PVVFL("[_localWeather]-space-[_verticalSeparator]-space-[_addLocation]"), ]).withViews(NSDictionaryOfVariableBindings(_localWeather, _verticalSeparator, _addLocation)) .withMetrics(@{@"space": @11}).asArray]; 

Parus can also handle incorrect cases, for example

 Constraint(_verticalSeparator, CenterY, Equal, _top, Width, +22) 

and others.

0
source

Source: https://habr.com/ru/post/1491407/


All Articles