Reputation: 29896
How can view layouts such as this, where the subviews are in vertical and horizontal relationships, be described using the Visual language?
Upvotes: 0
Views: 158
Reputation: 31745
Here is one way to do it. Assumptions: views 1 and 2 have a fixed pixel width, view 3 fills remaining width, fixed margin all round and between views. Views 1 and 2 equal height.
If those are wrong assumptions its pretty straightforward to extend this example.
Swift:
let views = ["view1": view1, "view2": view2, "view3": view3]
let metrics = ["m":12,"w":100]
let format0 = "H:|-(m)-[view1(w)]-(m)-[view3]-(m)-|"
let format1 = "H:|-(m)-[view2(w)]-(m)-[view3]-(m)-|"
let format2 = "V:|-(m)-[view1]-(m)-[view2(==view1)]-(m)-|"
let format3 = "V:|-(m)-[view3]-(m)-|"
for string in [format0,format1,format2,format3] as [String] {
self.view.addConstraints(
NSLayoutConstraint.constraintsWithVisualFormat(
string,
options:nil,
metrics:metrics,
views:views))
}
Objective-C:
NSDictionary* views = NSDictionaryOfVariableBindings(view1,view2,view3);
NSDictionary* metrics = @{@"m":@(12),@"w":@(100)};
NSString* format0 = @"H:|-m-[view1(w)]-m-[view3]-m-|";
NSString* format1 = @"H:|-m-[view2(w)]-m-[view3]-m-|";
NSString* format2 = @"V:|-m-[view1]-m-[view2(==view1)]-m-|";
NSString* format3 = @"V:|-m-[view3]-m-|";
for (NSString* string in @[format0,format1,format2,format3]) {
[self.view addConstraints:
[NSLayoutConstraint constraintsWithVisualFormat:string
options:0
metrics:metrics
views:views]];
}
The views under autolayout control need to have their translatesAutoresizingMaskIntoConstraints
property set to NO
(it defaults to YES
).
In one of your comments you say that the views 'already know their frames'. This sounds a little confused: when using autolayout, views don't set frames, frames are the result of the autolayout equations (the autolayout mechanism sets them).
In any case whether or not you use autolayout, views shouldn't set their own frames, that should be the job of the view's superview context. The superview, or its viewController would make frame decisions, as a frame positions a view with respect to the superview.
It sounds like you may mean that the views already know their sizes, based on their content (in the same way that buttons and labels know their sizes). In this case they can return a size value by overriding -(CGSize) intrinsicContentSize
in a UIView subclass. Then you can then omit size metrics from the format strings, simplifying them to:
Swift:
let format0 = "H:|-m-[view1]-m-[view3]-m-|"
let format1 = "H:|-m-[view2]-m-[view3]-m-|"
let format2 = "V:|-m-[view1]-m-[view2]-m-|"
let format3 = "V:|-m-[view3]-m-|"
Objective-C:
NSString* format0 = @"H:|-m-[view1]-m-[view3]-m-|";
NSString* format1 = @"H:|-m-[view2]-m-[view3]-m-|";
NSString* format2 = @"V:|-m-[view1]-m-[view2]-m-|";
NSString* format3 = @"V:|-m-[view3]-m-|";
However if the sizes don't all add up (eg 3*m + view1.height + view2.height != superview.height) something's going to break, and you are losing the advantage of using autolayout to flexibly arrange your views to fill the available space.
Upvotes: 1