简体   繁体   中英

Resize NSView to its subview using auto layout

In Interface Builder I've added a NSScrollView with a NSImageView , some labels, a horizontal separator and a NSView . The NSScrollView looks like the following: NSScrollView

Every element has constraints from the top left, and both the separator and the custom view also have a constraints to the right.

Sometimes I need to change the content of the custom view. I do this with the following code ( options is the custom view, view is the view I want to display):

[view setTranslatesAutoresizingMaskIntoConstraints:NO];
options.subviews = [NSArray arrayWithObject:view];

// Fix the constraints.
NSDictionary *viewsDictionary = NSDictionaryOfVariableBindings(view);
[options addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[view]|" options:0 metrics:nil views:viewsDictionary]];
[options addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[view]|" options:0 metrics:nil views:viewsDictionary]];

This works to some extent: the correct content is displayed in the view and the content's width is changed according to the constraints. However, the height of the options view doesn't change, so some content of the view view is not displayed. I tried to change this by manually setting the frame, but that doesn't work. Also, I tried the following to set a constraint:

[options addConstraint:[NSLayoutConstraint constraintWithItem:options attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:view attribute:NSLayoutAttributeHeight multiplier:1 constant:0]];

Nothing works though. Does anyone know how I can fix this?

A second problem I noticed is that even when the content of the NSScrollView is larger than the NSScrollView itself, scrolling doesn't work. No scrollbar is displayed. How can I fix that?

I still can't get my head around these harder problems with constraints...

I managed to solve my problem. It turned out I really had two problems:

  1. I didn't set the correct constraints on the NSScrollView and its children;
  2. I changed the content of the custom view, but didn't change its height.

My fix to both problems follows below.


NSScrollView constraints

After adding a NSScrollView in Interface Builder and placing some UI elements in the document view (the clip view's child), I had the following interface (the white part of the window is the NSScrollView, don't look at the constraints for now): 接口

If you run this and resize the window, no scrollbars are displayed though. First of all we have to add top and leading constraints on the document view relative to its superview. Now we need to specify the size of the document view. This can be done in two ways, depending on your use-case:

  1. Add constraints for the width and height of the document view. This way the same scrollbars are always displayed. The document view will then not change size depending on the content though, unless you automatically update these constraints;
  2. Add constraints to every child of the document view, so that document view's width and height can be calculated. This was needed for my problem, and these constraints are displayed in the image above.

If you run this, everything works as expected. We still can't change the content of the custom view though, and that's a different problem.


Changing the custom view

Now we just need to change the content of the custom view. Since we set constraints on the custom view, these should also be changed. All of this is done with the following self-explanatory code (the custom view is named content ):

- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
    [content setAutoresizesSubviews:NO];
}

- (IBAction)button1:(id)sender {
    [self showContent:view1];
}

- (IBAction)button2:(id)sender {
    [self showContent:view2];
}

- (void)showContent:(NSView *)c {
    // Remove all constraints.
    [content removeConstraints:content.constraints];

    // Add a height constraint.
    NSLayoutConstraint *constraint = [NSLayoutConstraint constraintWithItem:content attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1.0 constant:c.frame.size.height];
    [content addConstraint:constraint];

    // Add a width constraint.
    NSLayoutConstraint *constraint = [NSLayoutConstraint constraintWithItem:content attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1.0 constant:c.frame.size.width];
    [content addConstraint:constraint];

    [c setTranslatesAutoresizingMaskIntoConstraints:NO];

    // Set the content.
    content.subviews = [NSArray arrayWithObject:c];

    // Add constraints from the content view to its child view.
    NSDictionary *viewsDictionary = NSDictionaryOfVariableBindings(c);
    [content addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[c]|" options:0 metrics:nil views:viewsDictionary]];
    [content addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[c]|" options:0 metrics:nil views:viewsDictionary]];
}

I hope this answer saves someone else the trouble of finding out about the strange behavior with NSScrollView and autolayout.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM