WWDC Quick Look đź’“ By SwiftGGTeam
Build a UIKit app with the new design

Build a UIKit app with the new design

Watch original video

Highlight

A full breakdown of how to adopt the iOS 26 new design at the UIKit layer, covering six areas: Tab, navigation bar, Presentation, search, controls, and custom Glass.


Core content

Recompile an old app against the iOS 26 SDK and the Tab Bar floats, the navigation bar turns translucent, and buttons grow a Liquid Glass background. The question is what to do next. The old UIBarAppearance, backgroundColor, and custom button tints you added “for a unified look” now cover up the glass effect. Sanaa, an engineer on the UIKit team, spends nearly 25 minutes walking through the details you have to rethink across six areas.

The thread of the whole video is this: UIKit has redone the materials and layout of Tab Bar, Split View, Navigation Bar, Toolbar, Presentation, Search Bar, Slider, Switch, and so on. The developer’s job is to delete the old customization code, then use the new APIs to configure the few details the automatic behavior cannot handle. For example, scroll-to-minimize on the Tab Bar takes one line of tabBarMinimizeBehavior; extending artwork beneath a sidebar uses UIBackgroundExtensionView; the morph transition for sheets uses preferredTransition = .zoom; custom glass goes through UIGlassEffect plus UIVisualEffectView. Each API maps to a concrete scenario, no vague talk about “flexibility.”


Details

Tab Bar and bottom Accessory (from 02:31)

// Minimize tab bar on scroll
tabBarController.tabBarMinimizeBehavior = .onScrollDown

// Add a bottom accessory
let nowPlayingView = NowPlayingView()
let accessory = UITabAccessory(contentView: nowPlayingView)
tabBarController.bottomAccessory = accessory

Key points:

  • tabBarMinimizeBehavior = .onScrollDown: scroll down to hide the Tab Bar, scroll up to bring it back, leaving the focus on content.
  • UITabAccessory: hangs an auxiliary view above the Tab Bar, such as the Mini Player in a music app.
  • When the Tab Bar minimizes, bottomAccessory animates inline into the Tab Bar and takes less space.

Adaptive accessory views (03:35):

// Update the accessory with the trait
registerForTraitChanges([UITraitTabAccessoryEnvironment.self]) { (view: MiniPlayerView, _) in
    let isInline = view.traitCollection.tabAccessoryEnvironment == .inline
    view.updatePlayerAppearance(inline: isInline)
}

// Automatic trait tracking with updateProperties()
override func updateProperties() {
    super.updateProperties()
    let isInline = traitCollection.tabAccessoryEnvironment == .inline
    updatePlayerAppearance(inline: isInline)
}

Key points:

  • Watch the UITraitTabAccessoryEnvironment trait for the inline vs. standalone state.
  • Inline mode is tight on space, so hide secondary controls (the music app hides some playback controls).
  • updateProperties() is the automatic trait-tracking entry point introduced at WWDC25; see “What’s new in UIKit.”

Artwork extension beneath the sidebar (05:51)

// Extend content underneath the sidebar
let posterImageView = UIImageView(image: ...)

let extensionView = UIBackgroundExtensionView()
extensionView.contentView = posterImageView
view.addSubview(extensionView)

let detailsView = ShowDetailsView()
view.addSubview(detailsView)

Key points:

  • UIBackgroundExtensionView fills its content view (the poster) into the area outside the safe area.
  • It extends along the safe area by default: the top stays clear for the status bar / navigation bar, the leading edge for the Sidebar.
  • Anything you do not want extended (the show title, the episode list) goes in as a sibling, not inside extensionView.

Navigation bar grouping and subtitles (08:38 / 10:15)

// Custom grouping
navigationItem.rightBarButtonItems = [
    doneButton,
    flagButton, folderButton, infoButton,
    .fixedSpace(0),
    shareButton, selectButton
]

// Titles and subtitles
navigationItem.title = "Inbox"
navigationItem.subtitle = "49 Unread"

Key points:

  • The system groups buttons by rule: icon buttons share a glass background; text buttons, Done/Close, and prominent style get their own background.
  • .fixedSpace(0) forces same-kind buttons into two groups — the example splits Share off from the rest.
  • navigationItem.subtitle is a new API in iOS 26, rendered below the title; largeSubtitleView puts an interactive view below the large title (like Mail’s filter button).
  • The large title now scrolls with content, so the scroll view has to extend all the way under the navigation bar.

Edge Effect for custom containers (11:20)

// Edge effect's custom container
let interaction = UIScrollEdgeElementContainerInteraction()
interaction.scrollView = contentScrollView
interaction.edge = .bottom
buttonsContainerView.addInteraction(interaction)

Key points:

  • A scroll view under a navigation bar / toolbar gets a visual treatment automatically (Scroll Edge Effect).
  • A custom container floating at the edge (a floating button cluster, for example) needs UIScrollEdgeElementContainerInteraction to wire the edge effect behind it; otherwise the text under the container smears.

Zoom Transition and Action Sheet anchors (13:55)

// Morph popover from its source button
viewController.popoverPresentationController?.sourceItem = barButtonItem

// Morph sheet from bar button
viewController.preferredTransition = .zoom { _ in
    folderBarButtonItem
}

// Setting source item for action sheets
alertController.popoverPresentationController?.sourceItem = barButtonItem

Key points:

  • sourceItem points at the source button, and the popover morphs out of the button’s position.
  • preferredTransition = .zoom { ... } is for sheet-style pages: the button shape melts into the new page.
  • Action Sheets on iPhone now anchor to the source item too, matching iPad behavior; with no source they show centered and add a Cancel button automatically.

Search bar placement (15:36 / 17:03)

// Place search bar in a toolbar
toolbarItems = [
    navigationItem.searchBarPlacementBarButtonItem,
    .flexibleSpace(),
    addButton
]

// Place search at the trailing edge of the navigation bar (iPad)
navigationItem.searchBarPlacementAllowsExternalIntegration = true

// Search as a dedicated view
navigationItem.preferredSearchBarPlacement = .integratedCentered

// Tab Bar search shortcut
searchTab.automaticallyActivatesSearch = true

Key points:

  • On iPhone, move the search bar into the toolbar with searchBarPlacementBarButtonItem.
  • On iPad, set searchBarPlacementAllowsExternalIntegration and the system places the search bar at the trailing edge of the navigation bar (macOS style).
  • A Search Tab on the Tab Bar with automaticallyActivatesSearch = true expands directly into a text field on tap.

Controls: Glass Button, Slider, Switch (17:52)

// Standard glass
button.configuration = .glass()

// Prominent glass
tintedButton.configuration = .prominentGlass()

// Neutral slider with 5 ticks and a neutral value
slider.trackConfiguration = .init(allowsTickValuesOnly: true,
                                  neutralValue: 0.2,
                                  numberOfTicks: 5)

// Thumbless slider
slider.sliderStyle = .thumbless

Key points:

  • .glass() and .prominentGlass() are two new factory methods on UIButton.Configuration.
  • Slider gains a tick mode (allowsTickValuesOnly), a neutral anchor (neutralValue, e.g. the zero point of a brightness slider in Photos), and a .thumbless style.
  • The thumb on Switch and Segmented Control gets the Liquid Glass interaction animation.

Custom Glass: UIGlassEffect and containers (20:28 / 23:52)

// Adopting glass for custom views
let effectView = UIVisualEffectView()
addSubview(effectView)

let glassEffect = UIGlassEffect()
glassEffect.tintColor = .systemBlue
glassEffect.isInteractive = true

UIView.animate {
    effectView.effect = glassEffect
}

// Adding glass elements to a container
let container = UIGlassContainerEffect()
let containerView = UIVisualEffectView(effect: container)

let view1 = UIVisualEffectView(effect: UIGlassEffect())
let view2 = UIVisualEffectView(effect: UIGlassEffect())
containerView.contentView.addSubview(view1)
containerView.contentView.addSubview(view2)

Key points:

  • Apply UIGlassEffect to a UIVisualEffectView. Wrap the assignment in UIView.animate to trigger the materialize animation; setting it to nil dematerializes.
  • tintColor tints the glass; isInteractive = true turns on the elastic feedback on press.
  • UIGlassContainerEffect puts several glass views in one container — they fuse when close, separate when apart; spacing sets the fuse-distance threshold.
  • cornerConfiguration = .containerRelative() makes a child view’s corner radius track the container’s inset automatically.

Key takeaways

1. Treat “automatic migration” as the first step of redoing the UI

Why it pays off: recompiling against the iOS 26 SDK gives you most Liquid Glass effects for free. Look at the automatic result first, then decide which spots need hand-tuning. Beats rewriting from scratch by a wide margin.

How to start: build the existing app with the new SDK, screenshot every screen for comparison, and split the diffs into “automatically better” and “automatically worse.” Take the wins as is; work only on the regressions.

2. Delete the old custom Bar appearance

Why it pays off: old code like UIBarAppearance, backgroundColor, and button tints fights the Glass material directly. You will not get the new design without removing it.

How to start: grep the project for UIBarAppearance / setBackgroundImage / barTintColor and remove what you can. Keep only the tintColor plus style = .prominent that the information itself needs.

3. Redo the sidebar content with UIBackgroundExtensionView

Why it pays off: on iOS 26, a sidebar looks best when content extends underneath it (see the TV app). One or two lines of UIBackgroundExtensionView get you there.

How to start: find the detail screens that contain a sidebar, wrap the background image (poster, cover, map) inside UIBackgroundExtensionView.contentView, and add show titles / lists as siblings. Turn off automaticallyPlacesContentView for custom layouts when you need to.

4. Add ScrollEdgeElementContainerInteraction to every custom floating container

Why it pays off: the automatic edge blur applies only to system bars. A custom floating button cluster that is not wired up will smear text and buttons together below it.

How to start: list every floating button cluster and quick-action bar; add UIScrollEdgeElementContainerInteraction to their container view and set the matching scrollView and edge.

5. Wrap custom controls with UIGlassEffect where it fits

Why it pays off: in-house playback controls, track pickers, and badges still drawn on solid color look detached from the system visuals. UIGlassEffect plus UIGlassContainerEffect pull them into the Liquid Glass system.

How to start: pick the most prominent custom floating panel as a pilot, wrap it in UIVisualEffectView, set tintColor and isInteractive, and put multiple elements inside UIGlassContainerEffect to verify the fuse animation.


Comments

GitHub Issues · utterances