我如何实现frameForAlignmentRect:/ alignmentRectForFrame:这样对齐rect之外的框架封装了子视图的框架?

时间:2015-08-25 16:59:08

标签: macos cocoa autolayout nsview

所以我现在让我的基于Auto Layout的容器在大多数情况下工作。在10.8(我需要在10.7及更高版本上运行),我看到了这一点:

Image 1

注意如何剪切NSProgressIndicator和NSPopUpButton的边。

经过一些实验,我发现覆盖alignmentRectInsets并在所有边上返回50像素的插图显示没有裁剪:

Image 2

在这两种情况下,控件都绑定到容器视图对齐rect的左右边缘,并带有H:|[view]|。我想这也会在其他版本的OS X上发生,但在这里最引人注目(并且在编写时我只能访问10.8和10.10安装)。

现在,使用每侧50像素的对齐矩形插图听起来不对。我不认为有任何控制需要超过50像素,但我宁愿正确地做这些。所以我的问题是:如何实施alignmentRectForFrame:frameForAlignmentRect:选择器来正确考虑子视图的框架和对齐方式?

现在,我正在考虑强制布局,然后观察每个子视图的帧和对齐方式,假设我最后一个子视图的对齐rect(0,0)(子视图是线性排列的)将是对齐的容器视图的rect(0,0)。但我不确定这种方法是否足以处理所有情况,我不确定是否可以按照这两个选择器所需的相同方式反转操作。减法,也许?

如果我上面描述的是解决方案,我可以使用alignmentRectInsets执行此操作,还是该方法返回的插图在视图的生命周期内是否永远不会更改?

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

在下面的示例程序中,从没有命令行参数开始模拟第一个屏幕截图,并以模拟第二个屏幕截图的参数开始。选中Spaced复选框以向视图添加间距。

谢谢!

// 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;
}

0 个答案:

没有答案