记一次 contentInsetAdjustmentBehavior 引发的bug
注:本文同步发布于微信公众号:stringwu的互联网杂谈记一次 contentInsetAdjustmentBehavior 引发的bug
1 背景
项目中使用到了UILable
来展示相关的文本内容,但内容的大小不确定,有可能会超过屏幕的大小,因此需要在外层嵌套一个UIScrollView
来保证内容可以被完全展现给用户,在UILabel确定相关的高度后,再通过设置UIScrollView
的contentSize
来限定UIScrollView
的滚动范围,保证全部内容可被浏览。
2 实现代码
2.1 伪代码
class CustomView: UIView {
let scrollView: UIScrollView
let titleLabel: UILabel = UILabel()
.......
required init() {
scrollView = UIScrollView.init(frame: CGRect.init(x: 0, y: 0, width: 350, height: screen.height ))
.........
self.addSubview(scrollView)
self.scrollView.addSubview(titleLabel)
}
.....
override func layoutSubviews() {
super.layoutSubviews()
//让titleLabel 距离顶部的距离为30
titleLabel.frame = CGRect.init(x: 0, y: 30, width: self.scrollView.frame.width - 5, height: 80)
titleLabel.textAlignment = NSTextAlignment.left
titleLabel.lineBreakMode = NSLineBreakMode.byWordWrapping
titleLabel.numberOfLines = 0
titleLabel.sizeToFit()
//设置scrollView的可滚动范围为 titleLabel的高度加上上面的距离30
scrollView.contentSize = CGSize(width: 0, height: titleLabel.frame.height + 30)
..............
}
............
}
2.2 现象
在按照2.1的方式实现之后,发现titleLabel距离顶部的距离远远不止30那么少,估计都有60了,根本没有达到实际想要的效果,而且不同机器上表现出来还不一样。
3 问题的分析
在发现实现的效果没有达到想要的效果后,就开始进入问题的分析排查阶段。
3.1 排查方向一
一开始就是怀疑自己代码实现有问题,可能是其他地方也设置了距离顶部的top值,因此就尝试缩减给予titleLable
的初始的y
值
//titleLabel.frame = CGRect.init(x: 0, y: 30, width: self.scrollView.frame.width - 5, height: 80)
titleLabel.frame = CGRect.init(x: 0, y: 10, width: self.scrollView.frame.width - 5, height: 80)
把titleLable
的初始y
值从30逐渐缩小于10,但测试发现不管怎样改这个初始的y
值,实现的效果其实都差不多,根本没有办法缩小其距离顶部的距离。因此就排除了初始y
值设置不对引起的距离过大的猜测。
3.2 排查方向二
在发现不是初始y
值的影响后,就猜测大概率是父View
的影响,仔细查看了父View的设置代码后,发现其并没有设置顶部Top的距离,一行行代码排查后,怀疑是ContentSize
的设置引起的,故注释掉了设置ContentSize
的那一行设置:
override func layoutSubviews() {
super.layoutSubviews()
...........
//设置scrollView的可滚动范围为 titleLabel的高度加上上面的距离30
//scrollView.contentSize = CGSize(width: 0, height: titleLabel.frame.height + 30)
..............
}
注释掉这一行代码后,发现问题消失了,但由于没有设置scrollview
的contentSize
,整体scrollView
没有办法滚动了。这不科学啊,这个只是用来设置可滚动范围的接口啊,难道是我设置的高度太多了?但在尝试设置了多个不同的高度后,发现都没有解决问题。让我有点怀疑人生了。
3.3 排查方向三
在前面排查的方向都没有办法解决问题时,我已经没有其他任何的思绪了,只能去翻阅scrollView
的接口,查看是否有其他接口会影响到子View的位置情况,发现了一个属性contentInsetAdjustmentBehavior
,这个属性是在iOS11以上的系统才有的,并且在官方文档里的解释就是“决定内容偏移量的调整行为”,它的类型为UIScrollView.ContentInsetAdjustment
,主要有几个值:
- automatic :自动调整
- scrollableAxes: 只调整在可滚动方向的
- never : 不调整
- always : 在调整内容时,自己调整
并且在iOS 11以上的系统,该属性的默认值为always
,也就是说在你调整它的contentSize
时,系统会自动帮你调整子View的偏移量,这其实也解释了在排查方向二时出现的现象:调整了contenSize
时,整体的偏移量会多出很多的问题。
4 最终解决方式
在经历了多个怀疑方向的排查后,终于排查到了真正的问题所有,最终是通过禁用scrollview
的contentInsetAdjustmentBehavior
属性来解决问题:
if #available(iOS 11.0, *) {
scrollView.contentInsetAdjustmentBehavior = .never
}
真正修复问题的代码其实就只有一行,但排查到问题实际花费了我一天的时间,在学习iOS
的道路还任重道远