所以我现在让我的基于Auto Layout的容器在大多数情况下工作。在10.8(我需要在10.7及更高版本上运行),我看到了这一点:
注意如何剪切NSProgressIndicator和NSPopUpButton的边。
经过一些实验,我发现覆盖alignmentRectInsets
并在所有边上返回50像素的插图显示没有裁剪:
在这两种情况下,控件都绑定到容器视图对齐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;
}