【问题标题】:How to set dynamic height with Visual Format Language如何使用可视格式语言设置动态高度
【发布时间】:2024-04-15 19:50:02
【问题描述】:
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]];

使用 formatVertical 我可以设置视图的高度。但我想让这个值成为动态的,以便能够在所有不同的屏幕上以相同的外观显示。

有什么我可以做到的吗?

【问题讨论】:

  • 您希望它成为超级视图(屏幕)的百分比吗?如果是这样,你不能用 VFL 做到这一点
  • 用动态解释你的确切意思
  • 如果你是这个意思:*.com/questions/47594682/… 你不能。但是你能解释一下你到底需要什么吗?
  • 所以,我的意思是对所有屏幕尺寸(iPhone 5、iPhone X、iPhone 7 等)都有通用约束。例如,我想让我的 formatVertical 为屏幕的 0.5,这样高度就会无论 iPhone 屏幕的高度如何,都是所有屏幕类型的一半。 @DonMag
  • 有没有办法为不同的屏幕尺寸应用通用高度值?因为如果我设置为 V:|-40-[self(300)]|像这样它对 iphone5s 来说会很大,但对 iphone7 来说会小一点。 @Larme

标签: ios objective-c nslayoutconstraint visual-format-language


【解决方案1】:

Visual Format Language 很不错,除了有一些布局属性它不能做 - 例如高度/宽度百分比和居中。

来自“K. Davydenko”的答案起作用......有点。不过,它仍然为您的子视图设置了一个固定的高度。因此,如果您将其放在错误的位置(例如,在超级视图布局之前),或者如果视图发生变化(例如设备旋转),您将无法获得所需的内容。

由于除了 VFL 格式之外添加 NSLayoutConstraint 相当简单,因此这是更好的选择:

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

【讨论】:

    【解决方案2】:

    我认为,您可以使用指标。 Objective-C 解决方案:

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

    来自 raywenderlich.com 的 swift 解决方案:

    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

    【讨论】: