Macos 如何实现frameForAlignmentRect:/alignmentRectForFrame:以便对齐rect外部的框架封装子视图的框架?

Macos 如何实现frameForAlignmentRect:/alignmentRectForFrame:以便对齐rect外部的框架封装子视图的框架?,macos,cocoa,autolayout,nsview,Macos,Cocoa,Autolayout,Nsview,因此,我现在有我的自动布局为基础的容器工作,在大多数情况下。在10.8上(我需要在10.7及更高版本上运行),我看到: 请注意如何剪裁NSPROGESSINDICATOR和NSPOUPPBUTON的侧面 经过一些实验,我发现覆盖alignmentRectInsets并在所有侧面返回50个像素的insets不会显示任何剪辑: 在这两种情况下,控件都通过H:|[view]|绑定到容器视图对齐矩形的左边缘和右边缘。我想这也会发生在其他版本的OSX上,但这里最值得注意的是(在撰写本文时,我只能访问1

因此,我现在有我的自动布局为基础的容器工作,在大多数情况下。在10.8上(我需要在10.7及更高版本上运行),我看到:

请注意如何剪裁NSPROGESSINDICATOR和NSPOUPPBUTON的侧面

经过一些实验,我发现覆盖
alignmentRectInsets
并在所有侧面返回50个像素的insets不会显示任何剪辑:

在这两种情况下,控件都通过
H:|[view]|
绑定到容器视图对齐矩形的左边缘和右边缘。我想这也会发生在其他版本的OSX上,但这里最值得注意的是(在撰写本文时,我只能访问10.8和10.10安装)

现在,使用每侧50像素的对齐矩形插入听起来是错误的。我不认为有任何控件需要超过50像素,但我宁愿正确地执行这些操作。因此,我的问题是:如何实现
alignmentRectForFrame:
frameForAlignmentRect:
选择器来正确说明子视图的帧和对齐矩形

现在,我正在考虑强制布局,然后观察每个子视图的框架和对齐矩形,假设我最后一个子视图的对齐矩形(0,0)(子视图线性排列)将位于容器视图的对齐矩形(0,0)。但我不确定这种方法是否足以处理所有情况,我也不确定是否可以像这两个选择器所要求的那样反转操作。减法,也许

如果我上面描述的是解决方案,那么我可以使用
alignmentRectInsets
来实现这一点,还是该方法返回的insets必须在视图的生命周期内永不更改

或者第二个屏幕截图显示的场景是Interface Builder不会再现的,因此我认为从指导原则的角度来看是“错误的”

在下面的示例程序中,在不使用命令行参数的情况下启动以模拟第一个屏幕截图,并使用参数启动以模拟第二个屏幕截图。选中“间距”复选框以向视图添加间距

谢谢

// 17 august 2015
#import <Cocoa/Cocoa.h>

BOOL useInsets = NO;

@interface ContainerView : NSView
@end

@implementation ContainerView

- (NSEdgeInsets)alignmentRectInsets
{
    if (useInsets)
        return NSEdgeInsetsMake(50, 50, 50, 50);
    return [super alignmentRectInsets];
}

@end

NSWindow *mainwin;
NSView *containerView;
NSProgressIndicator *progressbar;
NSPopUpButton *popupbutton;
NSButton *checkbox;

void addConstraints(NSView *view, NSString *constraint, NSDictionary *views)
{
    NSArray *constraints = [NSLayoutConstraint constraintsWithVisualFormat:constraint
        options:0
        metrics:nil
        views:views];
    [view addConstraints:constraints];
}

void relayout(BOOL spaced)
{
    [containerView removeConstraints:[containerView constraints]];
    NSDictionary *views = @{
        @"pbar":        progressbar,
        @"pbutton": popupbutton,
        @"checkbox":    checkbox,
    };
    NSString *vconstraint = @"V:|[pbar][pbutton][checkbox]|";
    if (spaced)
        vconstraint = @"V:|[pbar]-[pbutton]-[checkbox]|";
    addConstraints(containerView, vconstraint, views);
    addConstraints(containerView, @"H:|[pbar]|", views);
    addConstraints(containerView, @"H:|[pbutton]|", views);
    addConstraints(containerView, @"H:|[checkbox]|", views);

    NSView *contentView = [mainwin contentView];
    [contentView removeConstraints:[contentView constraints]];
    NSString *base = @":|[view]|";
    if (spaced)
        base = @":|-[view]-|";
    views = @{
        @"view":        containerView,
    };
    addConstraints(contentView, [@"H" stringByAppendingString:base], views);
    addConstraints(contentView, [@"V" stringByAppendingString:base], views);
}

@interface appDelegate : NSObject<NSApplicationDelegate>
@end

@implementation appDelegate

- (IBAction)onChecked:(id)sender
{
    relayout([checkbox state] == NSOnState);
}

- (void)applicationDidFinishLaunching:(NSNotification *)note
{
    mainwin = [[NSWindow alloc]
        initWithContentRect:NSMakeRect(0, 0, 320, 240)
        styleMask:(NSTitledWindowMask | NSClosableWindowMask | NSMiniaturizableWindowMask | NSResizableWindowMask)
        backing:NSBackingStoreBuffered
        defer:YES];
    NSView *contentView = [mainwin contentView];

    containerView = [[ContainerView alloc] initWithFrame:NSZeroRect];
    [containerView setTranslatesAutoresizingMaskIntoConstraints:NO];

    progressbar = [[NSProgressIndicator alloc] initWithFrame:NSZeroRect];
    [progressbar setControlSize:NSRegularControlSize];
    [progressbar setBezeled:YES];
    [progressbar setStyle:NSProgressIndicatorBarStyle];
    [progressbar setIndeterminate:NO];
    [progressbar setTranslatesAutoresizingMaskIntoConstraints:NO];
    [containerView addSubview:progressbar];

    popupbutton = [[NSPopUpButton alloc] initWithFrame:NSZeroRect];
    [popupbutton setPreferredEdge:NSMinYEdge];
    NSPopUpButtonCell *pbcell = (NSPopUpButtonCell *) [popupbutton cell];
    [pbcell setArrowPosition:NSPopUpArrowAtBottom];
    [popupbutton addItemWithTitle:@"Item 1"];
    [popupbutton addItemWithTitle:@"Item 2"];
    [popupbutton setTranslatesAutoresizingMaskIntoConstraints:NO];
    [containerView addSubview:popupbutton];

    checkbox = [[NSButton alloc] initWithFrame:NSZeroRect];
    [checkbox setTitle:@"Spaced"];
    [checkbox setButtonType:NSSwitchButton];
    [checkbox setBordered:NO];
    [checkbox setFont:[NSFont systemFontOfSize:[NSFont systemFontSizeForControlSize:NSRegularControlSize]]];
    [checkbox setTarget:self];
    [checkbox setAction:@selector(onChecked:)];
    [checkbox setTranslatesAutoresizingMaskIntoConstraints:NO];
    [containerView addSubview:checkbox];

    [contentView addSubview:containerView];
    relayout(NO);

    [mainwin cascadeTopLeftFromPoint:NSMakePoint(20, 20)];
    [mainwin makeKeyAndOrderFront:mainwin];
}

- (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication *)app
{
    return YES;
}

@end

int main(int argc, char *argv[])
{
    useInsets = (argc > 1);

    NSApplication *app = [NSApplication sharedApplication];
    [app setActivationPolicy:NSApplicationActivationPolicyRegular];
    [app setDelegate:[appDelegate new]];
    [app run];
    return 0;
}
//2015年8月17日
#进口
BOOL useInsets=否;
@接口ContainerView:NSView
@结束
@实现容器视图
-(NSEdgeInsets)对齐矩形插入
{
如果(使用插图)
返回NSEdgeInsetsMake(50,50,50,50);
返回[超级对齐矩形插入];
}
@结束
NSWindow*mainwin;
NSView*容器视图;
进程指示器*进程条;
NSPOUPBUTTON*POUPBUTTON;
NSButton*复选框;
void addConstraints(NSView*视图、NSString*约束、NSDictionary*视图)
{
NSArray*约束=[NSLayoutConstraint constraints WithVisualFormat:constraint
选项:0
指标:零
意见:意见];
[查看添加约束:约束];
}
无效重新布置(布尔间隔)
{
[containerView removeConstraints:[containerView约束]];
NSDictionary*视图=@{
@“pbar”:progressbar,
@“按钮”:弹出按钮,
@“复选框”:复选框,
};
NSString*vconstraint=@“V:|[pbar][pbutton][checkbox]|”;
如果(间隔)
vconstraint=@“V:|[pbar]-[pbutton]-[checkbox]|”;
添加约束(containerView、vconstraint、视图);
添加约束(containerView,@“H:|[pbar]|”,视图);
添加约束(containerView,@“H:|[pbutton]|”,视图);
添加约束(containerView,@“H:|[复选框]|”,视图);
NSView*contentView=[mainwin contentView];
[contentView removeConstraints:[contentView约束]];
NSString*base=@:|[视图]|“;
如果(间隔)
基本=@:|-[view]-|“;
视图=@{
@“视图”:containerView,
};
addConstraints(contentView,[@“H”stringByAppendingString:base],视图);
addConstraints(contentView,[@“V”stringByAppendingString:base],视图);
}
@接口appDelegate:NSObject
@结束
@实现appDelegate
-(iAction)一旦检查:(id)发送方
{
重新启动([复选框状态]==NSON状态);
}
-(无效)ApplicationIDFinishLaunching:(NSNotification*)注释
{
mainwin=[[NSWindow alloc]
initWithContentRect:NSMakeRect(0、0、320、240)
样式掩码:(NSTitledWindowMask | NSClosableWindowMask | nsMinimableWindowMask | nsrEssizableWindowMask)
backing:NSBackingStoreBuffered
延期:是];
NSView*contentView=[mainwin contentView];
containerView=[[containerView alloc]initWithFrame:NSZeroRect];
[containerView设置翻译自动调整大小GMaskintoConstraints:否];
progressbar=[[NSProgressIndicator alloc]initWithFrame:NSZeroRect];
[progressbar setControlSize:NSRegularControlSize];
[进度条:是];
[progressbar设置样式:nsProgressIndicator或BarStyle];
[进度条设置不确定:否];
[进度条设置翻译自动调整大小GMaskintoConstraints:否];
[containerView addSubview:progressbar];
popupbutton=[[NSPopUpButton alloc]initWithFrame:NSZeroRect];
[popupbutton setPreferredEdge:NSMinYEdge];
NSPopUpButtonCell*pbcell=(NSPopUpButtonCell*)[popupbutton单元格];
[pbcell设置箭头位置:NSPopupParrowatBottom];
[popupbutton addItemWithTitle:@“第1项”];
[popupbutton addItemWithTitle:@“第2项”];
[弹出按钮设置翻译自动调整大小GMaskintoConstraints:否];
[containerView添加子视图:弹出按钮];
复选框=[[NSButton alloc]initWithFrame:NSZeroRect];
[复选框设置标题:@“间隔”];
[复选框setButtonType:NSSwitchButton];
[复选框:否];
[复选框setFont:[NSFont systemFontOfSize:[NSFont systemFontSizeForControlSize:NSRegularControlSize]];
[复选框setTarget:self];
[复选框setAction:@selector(一旦选中:)];
[复选框设置TranslatesAutoResizengMaskintoConstraints:否];
[containerView添加子视图:复选框];
[contentView添加子视图:containerView];
重新播放(否);
[mainwin cascadeTopLeftFromPoint:NSMakePoint(20,20)];