0

I have a vertical NSStackView that has this behavior. It has two subviews, one of them at top of the stack view, that will have a fixed height. Then, there is another view that will cover the remaining space in the view. Similar to the image below. My current code already displays the view as below:

enter image description here

I want to have a behavior where, when I hide the top view, or ViewA, the ViewB takes the height of the entire stack view. Like this image:

enter image description here

I'm doing this programmatically, but when I set the ViewA as hidden, the ViewB doesn't take the entire space available. Leaving the ViewA space there.

My current code already shows the UI like in the first image and it is:

@interface CutsomStackView : NSSTackView
@property (nonatomic) NSView *viewA;
@property (nonatomic) NSView *viewB;

- (id)initWithFrame:(NSRect)frame views:(NSArray<NSView *> *)views;
@end

@implementation CutsomStackView

- (id)initWithFrame:(NSRect)frame views:(NSArray<NSView *> *)views
{
    if (!(self = [super initWithFrame:frame]))
        return nil;

    _viewA = views[0];
    _viewB = views[1];

    self.detachesHiddenViews = YES;
    self.orientation = NSUserInterfaceLayoutOrientationVertical;
    self.spacing = 0;
    self.distribution = NSStackViewDistributionFill;

    CGFloat viewAHeight = NSHeight(_viewA.frame);

    [self addSubview:_viewA];
    [self addSubview:_viewB];

    _viewA.translatesAutoresizingMaskIntoConstraints = NO;
    _viewB.translatesAutoresizingMaskIntoConstraints = NO;

    NSDictionary *views = @{
        _viewA,
        _viewB
    };

    NSDictionary *metrics = @{
        @"viewAHeight": @(viewAHeight)
    };

    [NSLayoutConstraint activateConstraints:[NSLayoutConstraint constraintsWithVisualFormat:UNLOCALIZED_STRING("V:|[_viewA(viewAHeight)][_viewB]|") options:NSLayoutFormatAlignAllLeading | NSLayoutFormatAlignAllTrailing metrics:metrics views:views]];
    [NSLayoutConstraint activateConstraints:[NSLayoutConstraint constraintsWithVisualFormat:UNLOCALIZED_STRING("H:|[_viewA]|") options:0 metrics:nil views:views]];

    return self;
}

@end

I'm not sure what do I need to add to allow the ViewB to grow in size when the ViewA is hidden. In addition, after I hide the viewB, I call the layoutSubtreeIfNeeded method.

Jacobo
  • 1,259
  • 2
  • 19
  • 43
  • You just need to set the top and the bottom constraints. – El Tomato Dec 20 '20 at 05:33
  • Do I need to add bottom and top constraints to the `topView`? – Jacobo Dec 20 '20 at 05:34
  • Sorry, do you mean I need to add the constraints of the top and bottom anchors of the viewB relative to its superview? – Jacobo Dec 20 '20 at 05:40
  • ViewA needs a top constraint with a fixed value. ViewB needs a bottom constraint with a fixed value. – El Tomato Dec 20 '20 at 05:50
  • What about my current layout constraints, should I remove them? I don’t understand why the viewB only needs the bottom constraint and no other at top. – Jacobo Dec 20 '20 at 05:52
  • viewA needs a bottom constraint to viewB with a fixed value. viewB needs a top constraint to viewA with a fixed value. – El Tomato Dec 20 '20 at 05:54
  • Your approach doesn't even work. It actually broke the UI. I removed my constraints and I just left `[_viewB constraintEqualToAnchor:_viewA.bottomAnchor constant:0].active = YES; [_viewA.bottomAnchor constraintEqualToAnchor:_viewB.topAnchor constant:0].active = YES;` – Jacobo Dec 20 '20 at 06:07

1 Answers1

0

At the end the problem was in three different things:

  1. Using -[NSStackView addSubView:] instead of -[NSStackView addArrangedSubview:]
  2. Using a constraint to organize the views correctly.
  3. The hugging priority of the views.

The fixed code is:

@interface CutsomStackView : NSSTackView
@property (nonatomic) NSView *viewA;
@property (nonatomic) NSView *viewB;

- (id)initWithFrame:(NSRect)frame views:(NSArray<NSView *> *)views;
@end

@implementation CutsomStackView

- (id)initWithFrame:(NSRect)frame views:(NSArray<NSView *> *)views
{
    if (!(self = [super initWithFrame:frame]))
        return nil;

    _viewA = views[0];
    _viewB = views[1];

    self.detachesHiddenViews = YES;
    self.orientation = NSUserInterfaceLayoutOrientationVertical;
    self.spacing = 0;
    self.distribution = NSStackViewDistributionFill;

    CGFloat viewAHeight = NSHeight(_viewA.frame);

    [self addArrangedSubview:_viewA];
    [self addArrangedSubview:_viewB];

    _viewA.translatesAutoresizingMaskIntoConstraints = NO;
    [_viewA setContentHuggingPriority:NSLayoutPriorityRequired forOrientation:NSLayoutConstraintOrientationVertical];
    [_viewA.heightAnchor constraintEqualToConstant:topBarViewHeight].active = YES;
    

    _viewB.translatesAutoresizingMaskIntoConstraints = NO;
    [_viewB setContentHuggingPriority:NSLayoutPriorityDefaultLow forOrientation:NSLayoutConstraintOrientationVertical];

    return self;
}

@end
koen
  • 5,383
  • 7
  • 50
  • 89
Jacobo
  • 1,259
  • 2
  • 19
  • 43