面试题答案
一键面试约束语法差异
- iOS:在iOS中,常用的约束语法方式有以下几种:
- 使用
NSLayoutConstraint
类的constraintWithItem:attribute:relatedBy:toItem:attribute:multiplier:constant:
方法,例如:
- 使用
UIView *view1 = [[UIView alloc] init];
UIView *view2 = [[UIView alloc] init];
NSLayoutConstraint *constraint = [NSLayoutConstraint constraintWithItem:view1
attribute:NSLayoutAttributeLeading
relatedBy:NSLayoutRelationEqual
toItem:view2
attribute:NSLayoutAttributeLeading
multiplier:1.0
constant:10];
- 使用VFL(Visual Format Language),例如:
NSArray *constraints = [NSLayoutConstraint constraintsWithVisualFormat:@"H:|-10-[view1]-10-[view2]-10-|"
options:0
metrics:nil
views:@{@"view1": view1, @"view2": view2}];
- 使用
NSLayoutConstraint
的activateConstraints:
方法批量添加约束,例如:
[NSLayoutConstraint activateConstraints:@[constraint1, constraint2, constraint3]];
- macOS:在macOS中,约束语法与iOS类似,但视图类为
NSView
。也可以使用NSLayoutConstraint
类的方法,例如:
NSView *view1 = [[NSView alloc] init];
NSView *view2 = [[NSView alloc] init];
NSLayoutConstraint *constraint = [NSLayoutConstraint constraintWithItem:view1
attribute:NSLayoutAttributeLeading
relatedBy:NSLayoutRelationEqual
toItem:view2
attribute:NSLayoutAttributeLeading
multiplier:1.0
constant:10];
不同之处在于,macOS中可以使用NSStackView
来更方便地进行布局管理,它可以自动创建和管理子视图之间的约束。例如:
NSStackView *stackView = [[NSStackView alloc] initWithViews:@[view1, view2]];
stackView.orientation = NSUserInterfaceLayoutOrientationHorizontal;
布局优先级处理差异
- iOS:iOS中每个约束都有一个优先级(
UILayoutPriority
),默认优先级为UILayoutPriorityRequired
(1000)。当布局出现冲突时,优先级低的约束会被打破。例如,一个视图同时有水平方向的宽度约束和压缩阻力优先级不同的情况:
UIView *view = [[UIView alloc] init];
NSLayoutConstraint *widthConstraint = [NSLayoutConstraint constraintWithItem:view
attribute:NSLayoutAttributeWidth
relatedBy:NSLayoutRelationEqual
toItem:nil
attribute:NSLayoutAttributeNotAnAttribute
multiplier:1.0
constant:200];
widthConstraint.priority = UILayoutPriorityDefaultLow;
- macOS:macOS中同样有优先级概念,使用
NSLayoutConstraint
的priority
属性。但在实际应用中,macOS布局优先级的使用场景和iOS略有不同,例如在处理窗口大小变化时,对于一些固定大小视图和可拉伸视图的布局优先级设置。比如一个固定宽度的按钮和一个可拉伸的文本视图:
NSButton *button = [[NSButton alloc] init];
NSTextView *textView = [[NSTextView alloc] init];
NSLayoutConstraint *buttonWidthConstraint = [NSLayoutConstraint constraintWithItem:button
attribute:NSLayoutAttributeWidth
relatedBy:NSLayoutRelationEqual
toItem:nil
attribute:NSLayoutAttributeNotAnAttribute
multiplier:1.0
constant:100];
buttonWidthConstraint.priority = NSLayoutPriorityDefaultHigh;
视图特性差异
- iOS:iOS视图有一些特定的特性,如
contentMode
用于控制视图内容的显示方式(如UIViewContentModeScaleAspectFill
等),clipsToBounds
用于控制是否裁剪超出视图边界的内容。例如:
UIImageView *imageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"example"]];
imageView.contentMode = UIViewContentModeScaleAspectFill;
imageView.clipsToBounds = YES;
- macOS:macOS视图同样有类似功能,但命名和一些细节不同。例如
NSView
的wantsLayer
属性用于启用图层支持,进而可以设置类似裁剪等效果。NSImageView
的imageScaling
属性控制图片缩放方式,例如:
NSImageView *imageView = [[NSImageView alloc] init];
imageView.image = [NSImage imageNamed:@"example"];
imageView.imageScaling = NSImageScaleProportionallyUpOrDown;
imageView.wantsLayer = YES;
imageView.layer.masksToBounds = YES;
针对差异的代码编写示例
// 假设在一个跨平台项目中有一个视图,在iOS和macOS上都要实现相同的布局
// 1. 导入相关头文件
#ifdef TARGET_OS_IPHONE
#import <UIKit/UIKit.h>
#else
#import <AppKit/AppKit.h>
#endif
// 定义视图相关属性
#ifdef TARGET_OS_IPHONE
@interface MyViewController : UIViewController
@property (nonatomic, strong) UIView *mainView;
@end
#else
@interface MyViewController : NSViewController
@property (nonatomic, strong) NSView *mainView;
@end
#endif
@implementation MyViewController
- (void)viewDidLoad {
[super viewDidLoad];
#ifdef TARGET_OS_IPHONE
self.mainView = [[UIView alloc] init];
self.mainView.translatesAutoresizingMaskIntoConstraints = NO;
[self.view addSubview:self.mainView];
NSLayoutConstraint *leadingConstraint = [NSLayoutConstraint constraintWithItem:self.mainView
attribute:NSLayoutAttributeLeading
relatedBy:NSLayoutRelationEqual
toItem:self.view
attribute:NSLayoutAttributeLeading
multiplier:1.0
constant:20];
NSLayoutConstraint *topConstraint = [NSLayoutConstraint constraintWithItem:self.mainView
attribute:NSLayoutAttributeTop
relatedBy:NSLayoutRelationEqual
toItem:self.view
attribute:NSLayoutAttributeTop
multiplier:1.0
constant:20];
NSLayoutConstraint *widthConstraint = [NSLayoutConstraint constraintWithItem:self.mainView
attribute:NSLayoutAttributeWidth
relatedBy:NSLayoutRelationEqual
toItem:nil
attribute:NSLayoutAttributeNotAnAttribute
multiplier:1.0
constant:200];
NSLayoutConstraint *heightConstraint = [NSLayoutConstraint constraintWithItem:self.mainView
attribute:NSLayoutAttributeHeight
relatedBy:NSLayoutRelationEqual
toItem:nil
attribute:NSLayoutAttributeNotAnAttribute
multiplier:1.0
constant:100];
widthConstraint.priority = UILayoutPriorityDefaultLow;
[NSLayoutConstraint activateConstraints:@[leadingConstraint, topConstraint, widthConstraint, heightConstraint]];
self.mainView.backgroundColor = [UIColor redColor];
#else
self.mainView = [[NSView alloc] init];
self.mainView.translatesAutoresizingMaskIntoConstraints = NO;
[self.view addSubview:self.mainView];
NSLayoutConstraint *leadingConstraint = [NSLayoutConstraint constraintWithItem:self.mainView
attribute:NSLayoutAttributeLeading
relatedBy:NSLayoutRelationEqual
toItem:self.view
attribute:NSLayoutAttributeLeading
multiplier:1.0
constant:20];
NSLayoutConstraint *topConstraint = [NSLayoutConstraint constraintWithItem:self.mainView
attribute:NSLayoutAttributeTop
relatedBy:NSLayoutRelationEqual
toItem:self.view
attribute:NSLayoutAttributeTop
multiplier:1.0
constant:20];
NSLayoutConstraint *widthConstraint = [NSLayoutConstraint constraintWithItem:self.mainView
attribute:NSLayoutAttributeWidth
relatedBy:NSLayoutRelationEqual
toItem:nil
attribute:NSLayoutAttributeNotAnAttribute
multiplier:1.0
constant:200];
NSLayoutConstraint *heightConstraint = [NSLayoutConstraint constraintWithItem:self.mainView
attribute:NSLayoutAttributeHeight
relatedBy:NSLayoutRelationEqual
toItem:nil
attribute:NSLayoutAttributeNotAnAttribute
multiplier:1.0
constant:100];
widthConstraint.priority = NSLayoutPriorityDefaultLow;
[NSLayoutConstraint activateConstraints:@[leadingConstraint, topConstraint, widthConstraint, heightConstraint]];
self.mainView.wantsLayer = YES;
self.mainView.layer.backgroundColor = [NSColor redColor].CGColor;
#endif
}
@end
通过上述代码,在iOS和macOS上都实现了一个红色视图,距离父视图左上角20像素,宽度200像素,高度100像素,并且宽度约束优先级较低,以适应不同平台的布局差异。