How to set dynamic height with Visual Format Language

2.5k Views Asked by At
NSString *format = [NSString stringWithFormat:@"H:|-10-[self]-10-|"];
NSString *formatVertical = [NSString stringWithFormat:@"V:|-40-[self(300)]|"];
[constraints addObjectsFromArray:[NSLayoutConstraint constraintsWithVisualFormat:format options:0 metrics:nil views:viewsDictionary]];
[constraints addObjectsFromArray:[NSLayoutConstraint constraintsWithVisualFormat:formatVertical options:0 metrics:nil views:viewsDictionary]];

with formatVertical i am able to set height of my view. But i want to make this value as dynamic to be able to show in all different screens as same look.

Is there anything i can achieve this?

2

There are 2 best solutions below

0
DonMag On BEST ANSWER

Visual Format Language is nice, except there are a number of layout attributes it cannot do - such as height/width percentages and centering.

The answer from "K. Davydenko" will work... sort of. It still sets a fixed height for your subview though. So if you put that in the wrong place (before the superview is laid out, for example), or if the view changes (such as device rotation), you won't get what you're after.

Since it is rather simple to add a NSLayoutConstraint in addition to your VFL formatting, that's the better option:

UIView *v = [UIView new];
v.translatesAutoresizingMaskIntoConstraints = NO;
v.backgroundColor = [UIColor blueColor];

[self.view addSubview:v];

NSDictionary *viewsDictionary = @{@"self":v};

NSString *format = [NSString stringWithFormat:@"H:|-10-[self]-10-|"];

// vertical formatting (40-pts from the top), but do NOT set a height 
// (and do not include the trailing "|")
NSString *formatVertical = [NSString stringWithFormat:@"V:|-40-[self]"];

NSMutableArray *constraints = [NSMutableArray new];

[constraints addObjectsFromArray:[NSLayoutConstraint constraintsWithVisualFormat:format options:0 metrics:nil views:viewsDictionary]];
[constraints addObjectsFromArray:[NSLayoutConstraint constraintsWithVisualFormat:formatVertical options:0 metrics:nil views:viewsDictionary]];

// now add a constraint to set the Height of your subview equal to
// the height of the superview, with a 0.5 multiplier
// This will keep your view 1/2 the height of the superview, even
// when the superview's size changes
NSLayoutConstraint *c = [NSLayoutConstraint
                         constraintWithItem:v
                         attribute:NSLayoutAttributeHeight
                         relatedBy:NSLayoutRelationEqual
                         toItem:self.view
                         attribute:NSLayoutAttributeHeight
                         multiplier:0.5
                         constant:0.0];

[constraints addObject:c];

[self.view addConstraints:constraints];
0
K. Davydenko On

I think, you can use metrics. Objective-C solution:

NSString *format = [NSString stringWithFormat:@"H:|-10-[self]-10-|"];
NSString *formatVertical = [NSString stringWithFormat:@"V:|-40-[self(height)]|"];
NSNumber *height = [NSNumber numberWithFloat:self.view.frame.size.height / 2];
NSDictionary *metrics = [NSDictionary dictionaryWithObjectsAndKeys:height, @"height", nil];
[constraints addObjectsFromArray:[NSLayoutConstraint constraintsWithVisualFormat:format options:0 metrics:nil views:viewsDictionary]];
[constraints addObjectsFromArray:[NSLayoutConstraint constraintsWithVisualFormat:formatVertical options:0 metrics:metrics views:viewsDictionary]]; 

Solution for swift from raywenderlich.com:

private enum Metrics {
      static let padding: CGFloat = 15.0
      static let iconImageViewWidth: CGFloat = 30.0
    }
let metrics = [
      "horizontalPadding": Metrics.padding,
      "iconImageViewWidth": Metrics.iconImageViewWidth]

let topRowHorizontalFormat = """H:|-horizontalPadding-[iconImageView(iconImageViewWidth)]-[appNameLabel]-[skipButton]-horizontalPadding-|"""
let topRowHorizontalConstraints = NSLayoutConstraint.constraints(
    withVisualFormat: topRowHorizontalFormat,
    options: [.alignAllCenterY],
    metrics: metrics,
    views: views)
allConstraints += topRowHorizontalConstraints

let summaryHorizontalConstraints = NSLayoutConstraint.constraints(
    withVisualFormat: "H:|-horizontalPadding-[summaryLabel]-horizontalPadding-|",
    metrics: metrics,
    views: views)
allConstraints += summaryHorizontalConstraints

https://www.raywenderlich.com/174078/auto-layout-visual-format-language-tutorial-2