在 iOS 开发中,UIView 是最常用的控件之一。而其子类之中,最为特殊的就是 UIScrollView 了。因为 UIScrollView 具有独特的滚动特性,因此它关于子视图布局的方式也与普通的 UIView 不同,这就需要使用到 layoutSubviews() 方法。
layoutSubviews() 方法是 UIView 中的一个重要的布局方法,它的主要作用是对视图中所有子视图进行布局。在默认情况下,UIKit 会在初始化时调用该方法来完成对子视图的初始布局,在视图尺寸发生变化时也会自动调用。
那么,如何使用 layoutSubviews() 方法正确地布局子视图呢?以下是一些布局方式和注意事项。
一、 在自定义UIView中使用 layoutSubviews() 方法
在自定义 UIView 中,需要进行子视图的布局时,通常会在 layoutSubviews() 方法中完成。具体实现过程为:
1.首先,覆盖 layoutSubviews() 方法。
2.在 layoutSubviews() 方法中,对所有子视图进行位置&大小的设定。
3.布局完成后,调用 super.layoutSubviews() 。
示例:
```swift
class CustomView: UIView {
override func layoutSubviews() {
super.layoutSubviews()
//此处进行初始化布局或视图变化布局相关的操作
}
}
```
二、 在 UIScrollView 中使用 layoutSubviews() 方法
UIScrollView 同时包含基础的 UIView 和 UIScrollView 的属性和方法,同时也重写了若干原生方法。因此,在 UIScrollView 中布局时需要注意以下几点:
1.对于 UIScrollView,布局应该在 UIScrollView 的子视图中进行。
2.要调用 super.layoutSubviews()。
3.布局时一般需要对子视图和 contentSize 做修改。
示例:
```swift
class CustomScrollView: UIScrollView {
var customView = CustomView()
override func layoutSubviews() {
super.layoutSubviews()
// 设置 customView 的 frame 和布局
// 设置 contentSize
self.contentSize = CGSize(width: customView.frame.size.width, height: customView.frame.size.height)
}
}
```
三、懒加载子视图
有时候我们需要在 UIView 或 UIScrollView 中创建大量子视图,或者需要根据某个条件才能创建某个视图,这时,我们可以使用懒加载来创建控件,多个懒加载写成可读性高的计算属性。
示例:
```swift
class CustomScrollView: UIScrollView {
lazy var customView1: CustomView = {
let view = CustomView()
view.backgroundColor = .red
return view
}()
lazy var customView2: CustomView = {
let view = CustomView()
view.backgroundColor = .blue
return view
}()
override init(...){
super.init(...)
self.addSubview(customView1)
self.addSubview(customView2)
}
override func layoutSubviews() {
super.layoutSubviews()
// 设置 customView1 和 customView2 的 frame 和布局
// 设置 contentSize
self.contentSize = CGSize(width: customView1.frame.size.width, height: customView1.frame.size.height + customView2.frame.size.height)
}
}
```
四、使用 Auto Layout
使用 Auto Layout 可以是我们的代码更简洁易懂,且使得布局更灵活。在使用 Auto Layout 时:
1.布局代码应该写在 updateConstraints() 方法中,而不是 layoutSubviews() 中。
2.当前 layoutSubviews() 中仅需要调用 super.layoutSubviews() 即可。
3.对于 UIScrollView,如果使用了 Auto Layout,需要手动 Layout 子视图。
示例:
```swift
class CustomScrollView: UIScrollView {
var customView = CustomView()
override init(...){
super.init(...)
self.addSubview(customView)
customView.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
customView.leadingAnchor.constraint(equalTo: self.leadingAnchor),
customView.trailingAnchor.constraint(equalTo: self.trailingAnchor),
customView.heightAnchor.constraint(equalToConstant: 50),
customView.topAnchor.constraint(equalTo: self.topAnchor),
customView.bottomAnchor.constraint(equalTo: self.bottomAnchor),
])
self.layoutIfNeeded()
}
override func updateConstraints() {
super.updateConstraints()
//这里写 Autolayout 相关的约束
}
override func layoutSubviews() {
super.layoutSubviews()
// 设置 contentSize
self.contentSize = customView.frame.size
}
}
```
五、其他注意点
1.在 layoutSubviews() 中不应该再去执行过多逻辑,否则会卡顿应用。
2.尽量避免在 layoutSubviews() 或者 updateConstraints() 中频繁修改约束,容易出现循环调用的问题。
3.如果出现循环调用导致的死循环,debugging时可以将在调用 super 之前的部分注释掉,逐渐缩小范围。
4.如果 layoutSubviews() 运行过程中无法终止程序,说明逻辑上存在问题,或者某个视图无法成功布局,需要检查代码逻辑和视图约束。
结语
以上就是关于 layoutSubviews() 方法和子视图布局方式的一些总结和注意点。最终布局的效果和体验,除了依赖各种布局方式以外,也需要我们对视觉设计有强烈的感知和敏锐的判断能力。当然,这也需要通过不断学习,不断实践来获得。