NSStackView,当其中一个子视图被隐藏时填充视图

Posted

技术标签:

【中文标题】NSStackView,当其中一个子视图被隐藏时填充视图【英文标题】:NSStackView, fill view when one of the subviews is hidden 【发布时间】:2020-12-20 04:48:58 【问题描述】:

我有一个具有这种行为的垂直 NSStackView。它有两个子视图,其中一个位于堆栈视图的顶部,具有固定的高度。 然后,还有另一个视图将覆盖视图中的剩余空间。类似于下图。我当前的代码已经显示如下视图:

我希望有一种行为,当我隐藏顶视图或 ViewA 时,ViewB 采用整个堆栈视图的高度。喜欢这张图片:

我正在以编程方式执行此操作,但是当我将 ViewA 设置为隐藏时,ViewB 不会占用整个可用空间。将 ViewA 空间留在那里。

我当前的代码已经像第一张图片一样显示了 UI,它是:

@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

我不确定在隐藏 ViewA 时需要添加什么以允许 ViewB 增大。 另外,我隐藏viewB后,调用layoutSubtreeIfNeeded方法。

【问题讨论】:

只需要设置上下约束即可。 我是否需要在topView 中添加底部和顶部约束? 对不起,你的意思是我需要添加 viewB 的顶部和底部锚点相对于其父视图的约束吗? ViewA 需要一个具有固定值的顶部约束。 ViewB 需要一个具有固定值的底部约束。 我当前的布局约束怎么样,我应该删除它们吗?我不明白为什么 viewB 只需要底部约束而顶部不需要其他约束。 【参考方案1】:

最后,问题出在三个不同的地方:

    使用-[NSStackView addSubView:] 代替-[NSStackView addArrangedSubview:] 使用约束正确组织视图。 视图的拥抱优先级。

固定代码为:

@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

【讨论】:

以上是关于NSStackView,当其中一个子视图被隐藏时填充视图的主要内容,如果未能解决你的问题,请参考以下文章

隐藏另一个子视图类的子视图

当一个新的视图控制器被推送到导航控制器时,将一个子视图保持在屏幕上的同一位置?

在IOS的Storyboard中隐藏子视图

隐藏stackview中的第一个子视图和其他在iOS 10.2上消失但不是11

调用removeFromSuperview后如何防止子视图释放自我?

当视图开始被隐藏时,约束会发生啥?