UIScrollView contentOffset 值略有错误
UIScrollView contentOffset value marginally wrong
我的 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
/屏幕/scrollView
宽度=390
halfWidth
= 195
scrollView.contentOffset.x
= -195
根据我们在代码中的计算结果证明上述所有值都是绝对正确的。
哪里不行
在 iPhone 12 mini 中,数据值如下所示:
ViewController
/屏幕/scrollView
宽度=375
halfWidth
= 187.5
scrollView.contentOffset.x
= -187.33333333333334
scrollView.contentOffset.x
的值本应是 -187.5
,但实际上是 -187.33333333333334
。
进一步观察所有其他设备
在观察模式时,我意识到 contentOffset 值的边际误差出现在满足以下两个条件的特定设备上:
- 条件一:设备宽度为奇数
- 条件二:设备比例因子为奇数
重现错误的示例设备 - iPhone 12 mini、11 Pro、X、XS。所有这些设备的屏幕宽度 375
和比例因子 3
.
为什么精度很重要
我的用例是我正在使用 UICollectionView
创建一个自定义滑块,它负责根据已发生的滚动量发出滑动的值/分数。在我上面提到的问题细节中,场景是针对没有发生滚动的情况,因此我对发出的值/分数的期望是 0
。但是,由于这个边际错误,每次用户尝试将其滚动到开头时,该值都会变成非零。
这是已知错误吗?有什么解决办法吗?
我已经创建了一个用于快速调试的示例项目。 You can clone it from here.
OS 会将您的控件放置在偶数像素边界上。
您正在将控件定位在 UI Space 中。所以系统会把你提供的坐标翻译成像素space,设置控件的位置(在像素边界上),但是return你的位置在UISpace.
所以它需要你在 UI space 中的偏移量并将其转换为像素 space:
偏移量 * 屏幕比例 = 像素偏移量
187.5 * 3 = 562.5 像素
但像素是真实的、有形的东西。没有半像素这样的东西。所以系统四舍五入,像素偏移量变成562像素。
当您将该偏移量转换回 UI space
像素偏移/屏幕比例=uispace偏移
562 / 3 = 187.3333...
这就是系统返回该值的原因。
我的 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
/屏幕/scrollView
宽度=390
halfWidth
=195
scrollView.contentOffset.x
=-195
根据我们在代码中的计算结果证明上述所有值都是绝对正确的。
哪里不行
在 iPhone 12 mini 中,数据值如下所示:
ViewController
/屏幕/scrollView
宽度=375
halfWidth
=187.5
scrollView.contentOffset.x
=-187.33333333333334
scrollView.contentOffset.x
的值本应是 -187.5
,但实际上是 -187.33333333333334
。
进一步观察所有其他设备
在观察模式时,我意识到 contentOffset 值的边际误差出现在满足以下两个条件的特定设备上:
- 条件一:设备宽度为奇数
- 条件二:设备比例因子为奇数
重现错误的示例设备 - iPhone 12 mini、11 Pro、X、XS。所有这些设备的屏幕宽度 375
和比例因子 3
.
为什么精度很重要
我的用例是我正在使用 UICollectionView
创建一个自定义滑块,它负责根据已发生的滚动量发出滑动的值/分数。在我上面提到的问题细节中,场景是针对没有发生滚动的情况,因此我对发出的值/分数的期望是 0
。但是,由于这个边际错误,每次用户尝试将其滚动到开头时,该值都会变成非零。
这是已知错误吗?有什么解决办法吗?
我已经创建了一个用于快速调试的示例项目。 You can clone it from here.
OS 会将您的控件放置在偶数像素边界上。
您正在将控件定位在 UI Space 中。所以系统会把你提供的坐标翻译成像素space,设置控件的位置(在像素边界上),但是return你的位置在UISpace.
所以它需要你在 UI space 中的偏移量并将其转换为像素 space:
偏移量 * 屏幕比例 = 像素偏移量
187.5 * 3 = 562.5 像素
但像素是真实的、有形的东西。没有半像素这样的东西。所以系统四舍五入,像素偏移量变成562像素。
当您将该偏移量转换回 UI space
像素偏移/屏幕比例=uispace偏移
562 / 3 = 187.3333...
这就是系统返回该值的原因。