ylliX - Online Advertising Network
Automatic Trait Tracking

Automatic Trait Tracking


In iOS 18, UIKit automatically tracks when you access a trait, removing the need to manually register for trait change notifications.

Automatic Trait Tracking (iOS 18)

In iOS 18, UIKit supports automatic trait tracking in layout update methods in views and view controllers. See the Apple documentation for the full list of supported methods. It includes UIView methods like layoutSubviews(), updatesConstraints(), and draw(CGRect). Supported UIViewController methods include viewWillLayoutSubviews(), updateViewConstraints(), and the updateConfiguration methods for buttons, collection and table view cells.

Any time UIKit calls one of these methods it notes which traits you access in the method. Then when one of those traits changes it automatically invalidates the view using setNeedsLayout, setNeedsUpdateConstraints, setNeedsDisplay, or setNeedsUpdateConifguration, as appropriate. This removes the need to manually register for trait changes.

For example, I have a UIView subclass that overrides draw(CGRect). My view draws a box, inside the view bounds. When the user chooses one of the accessibility sizes of dynamic type I want to increase the size of my box:

final class SquareView: UIView {
  override func draw(_ rect: CGRect) {
    var scale = 0.3
    if traitCollection.preferredContentSizeCategory.isAccessibilityCategory
    {
        scale = 0.6
    }
    
    let width = bounds.width * scale
    let height = bounds.height * scale
    let startX = (bounds.width / 2) - (width / 2)
    let startY = (bounds.height / 2) - (height / 2)
    
    let path = UIBezierPath()
    path.move(to: CGPoint(x: startX, y: startY))
    path.addLine(to: CGPoint(x: startX, y: startY + height))
    path.addLine(to: CGPoint(x: startX + width, y: startY + height))
    path.addLine(to: CGPoint(x: startX + width, y: startY))
    path.addLine(to: CGPoint(x: startX, y: startY))
    
    UIColor.blue.setStroke()
    UIColor.blue.setFill()
    path.stroke()
    path.fill()
  }
}

The draw(CGRect) method checks the preferredContentSizeCategory trait before drawning the box. Before iOS 18, I need to add the view initializers and register for content size category trait changes and then call setNeedsDisplay to trigger a new call to draw(CGRect):

  // pre-iOS 18
  override init(frame: CGRect) {
    super.init(frame: frame)
    setupView()
  }

  required init?(coder: NSCoder) {
    super.init(coder: coder)
    setupView()
  }

  private func setupView() {
    registerForTraitChanges([
        UITraitPreferredContentSizeCategory.self
      ],
      action: #selector(contentSizeChanged))
  }

  @objc private func contentSizeChanged() {
      setNeedsDisplay()
  }

In iOS 18, that’s no longer necessary. UIKit registers that I’m accessing the preferredContentSizeCategory trait in draw(CGRect) and automatically calls setNeedsDisplay anytime it changes.

Learn More



Source link

Leave a Reply

Your email address will not be published. Required fields are marked *