为什么 UIPickerTableViewWrapperCell 的“childView.convert(childView.bounds, to: parentView)”不等于“childView.frame”?

Why `childView.convert(childView.bounds, to: parentView)` is not equal to `childView.frame` for UIPickerTableViewWrapperCell?

按照我的理解,frame是使用父视图坐标系的view的位置和大小,bounds是使用自己坐标系的view的位置和大小,也就是说childView.convert(childView.bounds, to: parentView)应该等于childView.frame.

但是我发现UIPickerTableViewWrapperCell不是这样的,从图中可以看出,frame是(origin = (x = 0, y = 160032.44775782057), size = (width = 134, height = 30.248210824676789)),而convert(bounds, to: parentView)(origin = (x = -71.984082796011151, y = 160032.44585526528), size = (width = 134.04199076956854, height = 29.70736933068838))

为什么这两个值不同?

经过一些挖掘,我找到了 an instructive article 这可能有助于您理解为什么会出现这种看似不一致的情况。

为了避免以后出现问题link,我将在下面添加场景。

作者首先以在屏幕上绘制的矩形为例。他们使用以下函数打印出框架和边界值:

private func printAll() {
    print("=========================")
    print("X : ", self.orangeView.frame.origin.x)
    print("Y : ", self.orangeView.frame.origin.y)
    print("width : ", self.orangeView.frame.size.width)
    print("height : ", self.orangeView.frame.size.height)
    print("=========================")
    print("X : ", self.orangeView.bounds.origin.x)
    print("Y : ", self.orangeView.bounds.origin.y)
    print("width : ", self.orangeView.bounds.size.width)
    print("height : ", self.orangeView.bounds.size.height)
    print("=========================")
}

使用这个,它们最初以相等的宽度和高度开始:

=========================
X :  87.0
Y :  384.0
width :  240.0
height :  128.0
=========================
X :  0.0
Y :  0.0
width :  240.0
height :  128.0
=========================

然后他们对矩形执行变换以旋转它:

self.orangeView.transform = CGAffineTransform(rotationAngle: 5)

当然,这会导致元素的高度和宽度在父 (.frame) 范围内发生变化:

=========================
X :  111.58938416597198
Y :  314.7747071707769
width :  190.82123166805604
height :  266.45058565844624
=========================
X :  0.0
Y :  0.0
width :  240.0
height :  128.0
=========================

当然,这是因为通过旋转绘制的矩形,取景矩形的大小发生了变化,即使绘制的矩形没有改变尺寸。 Apple 也完全意识到这一点 as indicated in their documentation,声明如下:

Warning

If the transform property is not the identity transform, the value of this property is undefined and therefore should be ignored.

这很重要,因为我们可以从您提供的数据中推断出一些重要的行为。具体来说,如果我们忽略坐标,而是查看高度和宽度值,我们会看到以下差异:

frame:   (width = 134, height = 30.248210824676789)
bounds:  (width = 134, height = 32)
convert: (width = 134.04199076956854, height = 29.70736933068838)

查看图像中的 UI 元素本身,我们甚至看到垂直“挤压”的文本,表明这些元素很可能以某种方式应用了变换。这可能会导致 Apple 文档中指出的上述未定义行为。正如 Apple 在他们的文档中指出的那样,当转换 属性 不是身份转换时,应该忽略 属性 的值。

不幸的是,我们无法验证这就是问题的原因,因为 UIKit,据我了解,不共享它的源代码,但转换导致未定义的行为似乎我们可以合理得出的最佳解释。