参考文档
自从iPhoneX有了小刘海,iOS的布局就多了个绕不开话题--safeArea
。
safeAreaLayoutGuide
UIView的一个只读属性,#available(iOS 11.0, *),用来帮助你避免与系统元素重叠。
When the view is visible onscreen, this guide reflects the portion of the view that is not covered by navigation bars, tab bars, toolbars, and other ancestor views.
- 当视图在屏幕上可见时,
safeAreaLayoutGuide
反映该视图中没有被 navigation bars, tab bars, toolbars 和 其他祖先视图 遮盖的部分。
注意⚠️:即使这些视图是部分透明的,它们仍然会遮挡它们下面的内容。
// 设置 navigationBar 为透明的,safeAreaLayoutGuide也为上图右
navigationController?.navigationBar.setBackgroundImage(UIImage(), for: .default)
navigationController?.navigationBar.shadowImage = UIImage()
-
Status Bar 对于iPhone 8及以下的影响如下图:
image.png
-
允许横屏时
image.png
safeAreaInsets
也是只读属性,是Frame布局是的选择。
iPhone X竖屏时占满整个屏幕的控制器的view的safeAreaInsets是(44,0,34,0),横屏是(0,44,21,44)
参考文档 : NSLayoutAnchor
一、 Auto Layout 进化过程
Auto Layout 的核心就是 “约束” —— NSLayoutConstraint
1⃣️: VFL语言
VFL全称是Visual Format Language,翻译过来是“可视化格式语言”
举个例子🌰: @"H:|-20-[blueView]-20-|"
// 来个代码看一下
- (void)viewDidLoad{
[super viewDidLoad];
UIView *redView = [[UIView alloc]init];
redView.backgroundColor = [UIColor redColor];
redView.translatesAutoresizingMaskIntoConstraints= NO;
[self.view addSubview:redView];
UIView *blueView = [[UIView alloc]init];
blueView.backgroundColor = [UIColor blueColor];
blueView.translatesAutoresizingMaskIntoConstraints= NO;
[self.view addSubview:blueView];
//水平方向
NSString *hVFL=@"H:|-20-[redView]-30-[blueView(==redView)]-20-|";
NSArray *hCons =[NSLayoutConstraint constraintsWithVisualFormat:hVFL options:NSLayoutFormatAlignAllTop | NSLayoutFormatAlignAllBottom metrics:nil views:@{@"redView":redView,@"blueView":blueView}];
[self.view addConstraints:hCons];
//垂直方向
NSString *vVFL =@"V:|-20-[redView(50)]";
NSArray *vCons =[NSLayoutConstraint constraintsWithVisualFormat:vVFL options:0 metrics:nil views:@{@"redView":redView}];
[self.view addConstraints:vCons];
}
缺点:
- 约束越复杂,越难描述;
- 字符串越长,越容易出错;
- 只能描述相对约束,不能描述绝对约束(例如有视图A和B,可以表示A的宽是B的两倍,但无法表示A的宽是100pt)。
2⃣️:NSLayoutConstraint
来段代码体验一下:
// Creating constraints using NSLayoutConstraint
NSLayoutConstraint(item: subview,
attribute: .leading,
relatedBy: .equal,
toItem: view,
attribute: .leadingMargin,
multiplier: 1.0,
constant: 0.0).isActive = true
NSLayoutConstraint(item: subview,
attribute: .trailing,
relatedBy: .equal,
toItem: view,
attribute: .trailingMargin,
multiplier: 1.0,
constant: 0.0).isActive = true
缺点:
- 参数太多了,写个UI耗时费力。
3⃣️:NSLayoutAnchor
// Creating the same constraints using Layout Anchors
let margins = view.layoutMarginsGuide
subview.leadingAnchor.constraint(equalTo: margins.leadingAnchor).isActive = true
subview.trailingAnchor.constraint(equalTo: margins.trailingAnchor).isActive = true
相比较来说 NSLayoutAnchor 确实是目前Auto Layout最好的选择。
二、LayoutAnchor 布局入门
布局属性分为3类:
-
NSLayoutDimension(尺寸)
宽高(widthAnchor/heightAnchor) -
NSLayoutXAxisAnchor(水平方向,x轴)
左右(leftAnchor/rightAnchor),
前后(leadingAnchor/trailingAnchor),
水平中心(centerXAnchor) -
NSLayoutYAxisAnchor(垂直方向,y轴)
上下(topAnchor/bottomAnchor),
垂直中心(centerYAnchor),
上下基准线(firstBaselineAnchor/lastBaselineAnchor)
let imageView = UIImageView()
imageView.image = UIImage(named: "LoginDejaIcon")
imageView.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(imageView)
imageView.heightAnchor.constraint(equalToConstant: 80).isActive = true
imageView.widthAnchor.constraint(equalToConstant: 80).isActive = true
imageView.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
if #available(iOS 11.0, *) {
imageView.topAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.topAnchor, constant: -3).isActive = true
} else {
imageView.topAnchor.constraint(equalTo: self.view.topAnchor, constant: 47).isActive = true
}
重点解析:
- translatesAutoresizingMaskIntoConstraints
这个属性的意思也非常明显:就是把老式的AutoResizing
(指 frame、bounds、center 和 autoresizingMask)自动转化为约束。
因为日常都是手写UI(Not Xib), translatesAutoresizingMaskIntoConstraints (by default is true)
如要对一个View进行Auto Layout的布局时(如上文code)需要把给属性设为 false
。因为老式的AutoResizing的约束已经非常充分完全,再添加任何的约束都会导致冲突。
注意⚠️: translatesAutoresizingMaskIntoConstraints 其实是AutoResizing
和 AutoLayout
鱼与熊掌兼的桥梁, 既在你的代码里,既可以存在 :
imageView1.frame = CGRect(x: 0, y: 0, width: 80, height: 80)
亦可以存在 :
imageView2.topAnchor.constraint(equalTo: self.view.topAnchor, constant: 47).isActive = true
只是不能作用于 同一个View。
-
isActive
The receiver may be activated or deactivated by manipulating this property. Only active constraints affect the calculated layout. Attempting to activate a constraint whose items have no common ancestor will cause an exception to be thrown. Defaults to NO for newly created constraints.
默认为false,需要设置为true才能激活约束属性。
有两个便捷方法激活和使无效
/* Convenience method that activates each constraint in the contained array, in the same manner as setting active=YES. This is often more efficient than activating each constraint individually. */
@available(iOS 8.0, *)
open class func activate(_ constraints: [NSLayoutConstraint])
/* Convenience method that deactivates each constraint in the contained array, in the same manner as setting active=NO. This is often more efficient than deactivating each constraint individually. */
@available(iOS 8.0, *)
open class func deactivate(_ constraints: [NSLayoutConstraint])
举例如下:
NSLayoutConstraint.activate([
bottomView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
bottomView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
bottomView.heightAnchor.constraint(equalToConstant: CGFloat(kFunctionPanelHeight)),
bottomView.bottomAnchor.constraint(equalTo: view.layoutMarginsGuide.bottomAnchor)
])
赠品:
-
autoresizingMask
屏幕快照 2019-03-14 下午5.47.41.png
none:表示不随父视图的改变而改变
flexibleLeftMargin:表示随着父视图的改变自动调整view与父视图的左边距,保证view与父视图的右边距不变;
flexibleRightMargin:表示随着父视图的改变自动调整view与父视图的右边距,保证view与父视图的左边距不变;
flexibleTopMargin:表示随着父视图的改变自动调整view与父视图的上边距,保证下边距不变;
flexibleBottomMargin:表示随着父视图的改变自动调整view与父视图的下边距,保证上边距不变;
flexibleWidth:表示随着父视图的改变自动调整view的宽度,保证view与父视图左右边距不变;
flexibleHeight:表示随着父视图的改变自动调整view的高度,保证view与父视图的上下边距不变;
🌰:如此使用
self.view.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
网友评论