Objective C Visual Autolayout NSTextField dynamic height
Asked Answered
C

1

0

I am trying to create a dynamic size NSView using visual auto layout. I am trying to achieve something like the following diagram.

enter image description here

I added following constraints to achieve this.

[self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"|-15-[_iconImageView(39)]-12-[_textView(239)]-15-|"
                                                             options:NSLayoutFormatAlignAllTop metrics:nil views:views]];
[self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-15-[_textView]-4-[_mainButton]-5-|"
                                                             options: NSLayoutFormatAlignAllLeft metrics:nil views:views]];
[self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"[_mainButton]-15-[_secondaryButton]"
                                                             options:NSLayoutFormatAlignAllTop metrics:nil views:views]];

But this creates the following layout.

enter image description here

As per my understanding, the following VFL will layout _textView 15px from top and then layout _mainButton after 4px from _textView bottom. But in actual _mainbottom is layout after 4px from top of _textView. Am i missing something here?

@"V:|-15-[_textView]-4-[_mainButton]-5-|"

Update


I replaced NSTextView with NSTextField. But now the problem is, NSTextField does not grow more than a single line height, but NSTextField is multi-line. Complete code for layouting and setting up views is as follow.

-(void)setupView {
    _textField = [[NSTextField alloc] initWithFrame:NSZeroRect];
    [[_textField cell] setWraps:YES];
    [_textField setLineBreakMode:NSLineBreakByWordWrapping];
    [[_textField cell] setTitle:@"This is a _textView, This will contain dynamic resizing text."];

    [_textField setSelectable:NO];
    [_textField setEditable:NO];
    [_textField setDelegate:self];
    [_textField setBordered:NO];
    [_textField sizeToFit];
    [_textField setTranslatesAutoresizingMaskIntoConstraints:NO];
    [self addSubview:_textField];
    
    _iconImageView = [[NSImageView alloc] initWithFrame:NSZeroRect];
    [_iconImageView setImage:[NSImage imageNamed:@"notify-warning-icon"]];
    [_iconImageView setTranslatesAutoresizingMaskIntoConstraints:NO];
    [self addSubview:_iconImageView];
    
    _mainButton = [[NSButton alloc] init];
    _mainButton.translatesAutoresizingMaskIntoConstraints = NO;
    [_mainButton setTitle:@"_mainButton"];
    [self addSubview:_mainButton];
    
    _secondaryButton = [[NSButton alloc] init];
    _secondaryButton.translatesAutoresizingMaskIntoConstraints = NO;
    [_secondaryButton setTitle:@"_secondaryButton"];
    [self addSubview:_secondaryButton];
    
    NSDictionary *views = NSDictionaryOfVariableBindings(_textField,_iconImageView,_mainButton,_secondaryButton);
    [self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"|-15-[_iconImageView(39)]-12-[_textField(239)]-15-|"
                                                                 options:NSLayoutFormatAlignAllTop metrics:nil views:views]];
    [self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-15-[_textField]-4-[_mainButton]-5-|"
                                                                 options: NSLayoutFormatAlignAllLeft metrics:nil views:views]];
    [self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"[_mainButton]-15-[_secondaryButton]"
                                                                 options:NSLayoutFormatAlignAllTop metrics:nil views:views]];
    
    [self addConstraint:[NSLayoutConstraint constraintWithItem:self attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeHeight multiplier:0.f constant:320.f]];
}

enter image description here

But if it changed this

@"V:|-15-[_textField]-4-[_mainButton]-5-|"

with this

@"V:|-15-[_textField(>=40)]-4-[_mainButton]-5-|"

I get the following output

enter image description here

But the problem is textfield content is dynamic and could change at runtime, it could be 2 lines, 3 lines etc. So how could i add some height constraint to NSTextField that will change NSTextField height depending on its content.

Cryptozoic answered 8/4, 2015 at 23:26 Comment(6)
Since you posted diagrams and not real screenshots, it's hard to tell: does the text view really draw? I suspect it's getting 0 height due to lack of sufficient constraints to give it any other height. Also, is there a reason you're using a text view rather than a text field, with its built-in support for computing a height based on its content and preferredMaxLayoutWidth? For that matter, your window looks just like an NSAlert. Could you use one of those instead of reinventing it?Meprobamate
This is not a diagram Second is a screenshot. Actually i can definitely use a NSTextField, And text view does draw. Actually this will not be a window it will be a part of some view so i can not use NSAlertCryptozoic
@KenThomases I replaced NSTextView with NSTextField and posted the updated question.Cryptozoic
Did you set preferredMaxLayoutWidth on the text field? I'm not seeing that in the code. That is necessary for the text field to compute an intrinsic content size with a height big enough to hold the wrapped text.Meprobamate
Oh that solved it for me _textField(239) I thought defining 239 here would be enough. Thanks @KenThomases you can post the answer here for others and i will mark it as answer.Cryptozoic
@KenThomases There is another layout question i have posted if you could kindly have a look #29525077Cryptozoic
M
4

You can use a text field rather than a text view and set its preferredMaxLayoutWidth property.

By default, if preferredMaxLayoutWidth is 0, a text field will compute its intrinsic size as though its content were laid out in one long line (or, at least, without any maximum width). Even if you apply a constraint that limits its actual width, that doesn't change its intrinsic height and therefore it typically won't be tall enough to contain the text as wrapped.

If you set preferredMaxLayoutWidth, then the text field will compute its intrinsic size based on the text as wrapped to that width. That includes making its intrinsic height tall enough to fit.

Meprobamate answered 9/4, 2015 at 19:26 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.