Skip to content

What Is New After WWDC22 (SwiftUI)

A SwiftUI guide for coding agents. Also covers ios 16 swiftui features, navigationstack navigationdestination, layout protocol custom container, swift charts intro, presentationdetents bottom sheet, viewthatfits adaptive layout.

The iOS 16 and macOS 13 release reshaped SwiftUI: value-based navigation, the Layout protocol, Swift Charts, resizable sheets, and ViewThatFits. This is the map; each feature has its own deep-dive doc.

NavigationView is deprecated. NavigationStack binds the stack to an array of values, so navigation becomes data you can push, pop, and deep-link programmatically.

NavigationStack(path: $path) {
  List {
    ForEach(users) { user in
      NavigationLink(user.name, value: user)
    }
  }
  .navigationTitle("Users")
  .navigationDestination(for: User.self) { user in
    UserView(user: user)
  }
}
.onAppear {
  path.append(contentsOf: [.init(name: "Ada"), .init(name: "Grace")])
}

NavigationLink now carries a value, and navigationDestination(for:) maps that value type to its destination view.

The Layout Protocol

Conform to Layout and implement sizeThatFits plus placeSubviews to build a custom container. Measure children with subview.sizeThatFits(.unspecified), then place each with place(at:anchor:proposal:). The article's example sizes every child to the widest one, an equal-width HStack.

struct EqualWidthHStack: Layout {
  func sizeThatFits(proposal: ProposedViewSize, subviews: Subviews, cache: inout ()) -> CGSize {
    let maxSize = maxSize(subviews: subviews)
    let totalSpacing = spacings(subviews: subviews).reduce(0.0, +)
    return CGSize(
      width: maxSize.width * CGFloat(subviews.count) + totalSpacing,
      height: maxSize.height
    )
  }

  func placeSubviews(in bounds: CGRect, proposal: ProposedViewSize, subviews: Subviews, cache: inout ()) {
    let maxSize = maxSize(subviews: subviews)
    var x = bounds.minX + maxSize.width / 2
    for index in subviews.indices {
      subviews[index].place(
        at: CGPoint(x: x, y: bounds.midY),
        anchor: .center,
        proposal: ProposedViewSize(width: maxSize.width, height: maxSize.height)
      )
      x += maxSize.width + spacings(subviews: subviews)[index]
    }
  }
}

Swift Charts

The Charts framework draws declarative charts with accessibility and localization built in. Mix mark types inside one Chart.

Chart(items) { item in
  LineMark(x: .value("Index", item.index), y: .value("Value", item.value))
  BarMark(
    x: .value("Index", item.index),
    yStart: .value("Start", 0),
    yEnd: .value("End", item.value)
  )
  .foregroundStyle(by: .value("Value", item.value))
}

Resizable Sheets and ViewThatFits

presentationDetents turns a sheet into a draggable bottom sheet. The default is large; adding .medium lets the user drag between sizes.

.sheet(isPresented: $showSettings) {
  Text("Settings")
    .presentationDetents([.medium, .large])
}

ViewThatFits renders the first of its children that fits the available space, for example an HStack that degrades to a VStack. Also new: the Transferable protocol for share and drag-and-drop, the Grid view, and window and menu bar extra scenes.

Use this guidance in your coding agent

Install the Better Design MCP once. Your agent then loads this page with one call.

get-swiftui-guide({ topic: "swiftui-what-is-new-after-wwdc22" })
claude mcp add --scope user better-design --transport http https://better-design.com/api/mcp --header "Authorization: Bearer <YOUR_API_KEY>"
Browse related design systems