我的ViewController
中有一个scrollView
。scrollView
垂直居中放置,其宽度等于ViewController
的宽度,高度等于100
。为了使scrollView
可滚动,我为这个scrollView设置了一个任意的contentSize
,假设它是(500, 100)
。这有助于我的scrollView水平滚动。
我的要求是我想要scrollView
的内容从scrollView
的水平中心开始。因此,我在它上面设置了contentInset
值。
let halfWidth = scrollView.bounds.size.width / 2.0
scrollView.contentInset = UIEdgeInsets(top: 0, left: halfWidth, bottom: 0, right: halfWidth)
scrollView.contentOffset = CGPoint(x: -halfWidth, y: 0)
记住,我的scrollView
的宽度等于ViewController
的宽度。因此,上述代码中的halfWidth
值将与view.bounds.width / 2.0
相同。
在哪里工作
在iPhone 12 Pro中,数据值如下:
ViewController
/Screen/scrollView
width =390
halfWidth
=195
scrollView.contentOffset.x
=-195
以上所有的值都是绝对正确的,根据我们在代码中的计算。
不工作的地方
在iPhone 12 mini中,数据值如下:
ViewController
/Screen/scrollView
width =375
halfWidth
=187.5
scrollView.contentOffset.x
=-187.33333333333334
scrollView.contentOffset.x
的值应该是-187.5
,但实际是-187.33333333333334
。
用其他设备进一步观察
在观察这个模式时,我意识到这个contenttoffset值的边缘错误出现在满足以下两个条件的特定设备上:
- 条件1:设备宽度为奇数
- 条件2:设备比例因子为奇数。
复制错误的设备示例- iPhone 12 mini, 11 Pro, X, XS。这些器件的屏幕宽度为375
,比例系数为3
。
为什么精度很重要
我的用例是,我正在使用UICollectionView
创建一个自定义滑块,它负责根据已经发生的滚动量发出滑动的值/分数。在我上面提到的问题细节中,这个场景是针对没有发生滚动的情况,因此我对发出的值/分数的期望是0
。但是,由于这个边缘误差,每次用户试图滚动到开始时,该值都是非零的。
这是一个已知的错误吗?有什么方法可以解决这个问题吗?
我已经创建了一个示例项目用于快速调试。你可以从这里克隆它。
操作系统将把你的控件放在一个偶数像素的边界上。
您正在UI空间中定位控件。所以系统会将你提供的坐标转换为像素空间,设置控件的位置(在像素边界上),但在UI空间中返回位置给你。
它将你在UI空间中的偏移量转换为像素空间
offset * screen scale = pixel offset
187.5 * 3 = 562.5像素
但是像素是真实的,物理的东西。没有所谓的半像素。因此,系统四舍五入,像素偏移量变为562像素。
当你把偏移量转换回UI空间
像素偏移/屏幕比例= UI空间偏移
562/3 = 187.3333…
这就是为什么系统会返回这个值。