Search code examples
iosautolayoutuikit

systemLayoutSizeFitting(_:) does not respect width or height constraints for decimal numbers


let aView = UIView()
let width: CGFloat = 173.5
aView.widthAnchor.constraint(equalToConstant: width).isActive = true
print(aView.systemLayoutSizeFitting(CGSize(width: width, height: 0)))

Output (on iOS 13.7, may affect other versions):

(173.66666666666666, 0.0)

I've found using 0.33 or 0.66 as the fractional part makes the output slightly less wrong, but still has unwanted recurring digits e.g. 173.33333333333334 for 0.33

I've also reproduced this for height constraints. Using UIView.layoutFittingCompressedSize as the size also has the same incorrect output.

Is this a bug, or is this something I don't know about Auto Layout?


Solution

  • UIKit cannot draw on partial-pixels.

    On devices with @2x screen scale (such as iPhone 11), your result will be:

    (173.5, 0.0)  // nearest half-of-a-point
    

    On devices with @3x screen scale (such as iPhone 11 Pro), your result will be:

    (173.66666666666666, 0.0)  // nearest third-of-a-point
    

    Note that if you try:

    let width: CGFloat = 173.25
    

    you'll get:

    (173.33333333333334, 0.0)   // iPhone 11 Pro
    (173.5, 0.0)                // iPhone 11