记一次 contentInsetAdjustmentBehavior 引发的bug

注:本文同步发布于微信公众号:stringwu的互联网杂谈记一次 contentInsetAdjustmentBehavior 引发的bug

1 背景

项目中使用到了UILable来展示相关的文本内容,但内容的大小不确定,有可能会超过屏幕的大小,因此需要在外层嵌套一个UIScrollView来保证内容可以被完全展现给用户,在UILabel确定相关的高度后,再通过设置UIScrollViewcontentSize 来限定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)
       	..............
	}

注释掉这一行代码后,发现问题消失了,但由于没有设置scrollviewcontentSize,整体scrollView没有办法滚动了。这不科学啊,这个只是用来设置可滚动范围的接口啊,难道是我设置的高度太多了?但在尝试设置了多个不同的高度后,发现都没有解决问题。让我有点怀疑人生了。

3.3 排查方向三

在前面排查的方向都没有办法解决问题时,我已经没有其他任何的思绪了,只能去翻阅scrollView的接口,查看是否有其他接口会影响到子View的位置情况,发现了一个属性contentInsetAdjustmentBehavior,这个属性是在iOS11以上的系统才有的,并且在官方文档里的解释就是“决定内容偏移量的调整行为”,它的类型为UIScrollView.ContentInsetAdjustment,主要有几个值:

  • automatic :自动调整
  • scrollableAxes: 只调整在可滚动方向的
  • never : 不调整
  • always : 在调整内容时,自己调整

并且在iOS 11以上的系统,该属性的默认值为always,也就是说在你调整它的contentSize时,系统会自动帮你调整子View的偏移量,这其实也解释了在排查方向二时出现的现象:调整了contenSize时,整体的偏移量会多出很多的问题。

4 最终解决方式

在经历了多个怀疑方向的排查后,终于排查到了真正的问题所有,最终是通过禁用scrollviewcontentInsetAdjustmentBehavior 属性来解决问题:

    if #available(iOS 11.0, *) {
            scrollView.contentInsetAdjustmentBehavior = .never
        }

真正修复问题的代码其实就只有一行,但排查到问题实际花费了我一天的时间,在学习iOS的道路还任重道远

posted @ 2021-05-19 20:34  woodWu  阅读(515)  评论(0编辑  收藏  举报