Understanding Misaligned Images in the iOS Simulator
Today, we'll discuss this setting in more detail and we'll see how we can improve our app's rendering performance by addressing issues related to misaligned images.
I've been making iPhone apps for years, but I've never really investigated this feature. Now that I know what it does, I wonder how many of my previous apps have been dealing with this issue.
Let's make sure you don't make that same mistake.
Simply put, this feature helps you identify instances where a view's position and dimensions don't fully align with the pixels on a physical device.
The documentation for a CGPoint
shows that we can initialize it with fractional values:
CoreGraphics
does not complain if you try to render fractional pixels and will not raise any warnings. Instead, CoreGraphics
will perform anti-aliasing in order to render a fractional pixel as effectively as possible.
In other words, misaligned views' pixels need to be interpolated with surrounding pixels to determine accurate color values. This is not only computationally expensive but may also create blurry images.
Aliasing is the visual stair-stepping of edges that occurs in an image when the resolution is too low. Anti-aliasing is the smoothing of jagged edges in digital images by averaging the colors of the pixels at a boundary.
Adobe
If you calculate the dimensions of a view's frame rather than using AutoLayout constraints, you will often encounter misaligned images. Although frame-based layouts are becoming less common, you may still use this approach if you are building custom UI components, complex animations, etc.
So, let's intentionally create this problem and then figure out how to fix it:
- Magenta overlays are caused by subpixel misalignment
- Yellow overlays are caused by stretching
let rect = CGRect(x: 30.4, y: 50.4323, width: 100.12, height: 100.23)
let misalignedLabel = UILabel(frame: rect)
misalignedLabel.text = "Hello, world!"
view.addSubview(misalignedLabel)
To fix this issue, we can simply do the following:
Alternatively, we can leverage CGGeometry
's integral
property:
/// A rectangle with the smallest integer values for its origin and size that contains the source rectangle.
/// That is, given a rectangle with fractional origin or size values, integral rounds the rectangle’s origin
/// downward and its size upward to the nearest whole integers, such that the result contains the
/// original rectangle.
///
/// Returns a null rectangle if rect is a null rectangle.
let rect = CGRect(x: 30, y: 175, width: 100.12, height: 100.23)
let alignedViewIntegral = UILabel(frame: rect.integral)
alignedViewIntegral.text = "Hello, world!"
view.addSubview(alignedViewIntegral)
Both of these approaches resolve the issue:
I hope you now have a clearer understanding of how this feature works and how to resolve any misalignment issues you may encounter.
See you next time!
If you're interested in more articles about iOS Development & Swift, check out my YouTube channel or follow me on Twitter.
If you're an indie iOS developer, make sure to check out my newsletter:
I feature a new developer every issue, so feel free to submit your indie iOS apps!
Do you have an iOS Interview coming up?
Check out my book Ace The iOS Interview!