是个可以稳定复现,而且只用一行就能修复好的一个小bug.为什么说歹毒呢?一个是因为一开始找错方向浪费了几个小时,二来也是最歹毒的部分,就是我自己重开了个新项目,试图自己把这个bug敲出来,一直没成功……

问题本身是这么个问题(截图来自Chrome v131)——

Original Bug 1

这时候,如果你去手机设置里面把字体改大,大到下面的部分屏幕里放不下的时候,再回到app里面,你就会惊奇地发现……顶上那个图,竟然往下掉了一截!(人话是这么说的。我不是人,那么用我的话说就是本来应该应该顶端和superview顶端对齐的UIImageView竟然对齐到navigation bar底端了)

Original Bug 2

这是怎么回事呢?作为一个成(辣)熟(鸡)的iOS码农,我第一反应自然是constraints是怎么写的?我花了几个小时做了几件事情

  1. 生啃代码,基本上搞清楚了这个view继承的superview里面所有constraints的逻辑。不得不说,怪乱的,可以控制的参数忒也多
  2. 确认我从打开app到打开这个界面的全过程中,这坨屎山没有对nav bar做什么不该做的事情(其实是有的,但我后来确定了具体到我这个情况其实没影响)
  3. 自然是上xcode的view hierarchy debugger。当然,就像每一个成(辣)熟(鸡)码农一样,我也只看自己看得懂的部分,看不懂的先忽略——直到突然福至心灵地看懂了它

果然,步骤3重复了几十次以后,绞尽脑汁也没发现这个母类的constraints哪儿有问题以后……我注意到了一个我之前一直忽略的东西——

ScrollView Indicator

这上面的数值(尤其x和y)是什么应该是不言自明的了。然后——我当时看的时候,y = -52.

也就是说,问题不是出在排版/对齐上,而是因为某些原因,scrollview滚动进度初始值不是0,而是一个负数?

照着这个思路找答案就简单多了。没两分钟(搜对关键字的前两条结果就有)我就找到了罪魁祸首——UIScrollView.contentInsetAdjustmentBehavior。这里behavior指什么呢?就是指——要不要在scrollview里面把顶上的navigation bar以及各种边角可能有的遮挡(简称non-safeArea)的位置空出来。默认是automatic,所以顶上空不空出navigation bar的位置不是我自己控制的,不奇怪。修起来也很容易,多写一行scrollView.contentInsetAdjustmentBehavior = .never便万事大吉。

于是我就对iOS百思不得其解了——自动就自动吧,凭啥自大顶上就空出来,字小点儿就不空了?

更歹毒的是我当天回家麻溜儿试图复现。同样的Xcode和Simulator版本(应该是?),写了个UINavigationController上有UIScrollView,scrollview里面上面是个图下面是堆字儿,同样是用代码排版对齐的。然后我就完全复现不出来了。。。把contentInsetAdjustmentBehavior设成自动的时候,无论系统字体多小,顶上navigation bar都会空出来。于是我分外疑惑了,难道图和图的处理逻辑还不同不成?

PS:用中文写技术文真累啊,好多术语中文就特么没有翻译啊😂问我为啥不直接用英文写?我还真想过,然后发现如果我用英文写的话,和直接复制粘贴各种文档好像没啥区别,用中文至少我还得自己过脑子组织一遍语言,顺便当复习了。。。