Provide views, controls, and layout structures for declaring your app's user interface using SwiftUI.

SwiftUI Documentation

Posts under SwiftUI subtopic

Post

Replies

Boosts

Views

Activity

iOS 27 regression - minimized search item in top toolbar breaks its state
struct ContentView: View { @State var searchText: String = "" var body: some View { TabView { Tab { NavigationStack { List { Text("Hello!") Text("Hello!") Text("Hello!") Text("Hello!") Text("Hello!") Text("Hello!") } .navigationTitle("Have a title") .searchable(text: $searchText, placement: .toolbar) .searchToolbarBehavior(.minimize) .toolbar { DefaultToolbarItem(kind: .search, placement: .topBarTrailing) } } } } } } In iOS 26, this worked no problem. In iOS 27, this leaves the search bar either unable to collapse (when pressing the close button) or in a broken state where it cannot be opened again.
Topic: UI Frameworks SubTopic: SwiftUI
8
11
1.7k
15h
NavigationSplitView Binding to NavigationSplitViewColumn reset with every NavigationStack path change
I try to create a Navigation that works on iPhone, iPhone Duo and iPad. NavigationSplitView collapses for compact form factors and makes iPhone Duo support much simpler. The Problem is the semantic of the collapse. Switch from detail to sidebar on compact is not a 'back' action in my case. It should have my choosen Icon and has a meaning. So i wanted to control this using the NavigationSpliViewColumn Binding. This does work forward and backward as long as no NavigationStack was used before. But it stops working when you return to the detail root from a Navigation-Action. I left the Backbutton visible so you can test, that it continues to work, when no Navigation-Action preceeded the switch. Here is my Code: import SwiftUI @Observable final class Compass { var path: [Route] init() { self.path = [] } } enum Route: Hashable { case goal } struct ContentView: View { @Environment(\.horizontalSizeClass) private var hsize @State private var compass: Compass = Compass() @State var column: NavigationSplitViewColumn = .detail var body: some View { NavigationSplitView(preferredCompactColumn: $column) { OverviewScreen(column: $column) } detail: { TodayScreen() .toolbar { ToolbarItem(placement: .topBarLeading) { Button("overview", systemImage: "calendar") { self.column = .sidebar } } } } .environment(compass) .onChange(of: column) { old, new in print("column:", old, "→", new) } } } struct OverviewScreen: View { @Binding var column: NavigationSplitViewColumn @Environment(Compass.self) var compass var body: some View { @Bindable var compass = self.compass ScrollView { Text("Overview") .font(.largeTitle) .fontWeight(.heavy) Button("Switch") { self.column = .detail } } } } struct TodayScreen: View { @Environment(Compass.self) var compass var body: some View { @Bindable var compass = self.compass NavigationStack(path: $compass.path) { ScrollView { Text("Today") .font(.largeTitle) .fontWeight(.heavy) Button("Goals programtically", systemImage: "flag.fill") { self.compass.path = [.goal] } NavigationLink(value: Route.goal) { Label("Goal Link", systemImage: "flag.fill") } } .navigationDestination(for: Route.self, destination: self.screen) } } @ContentBuilder func screen(for route: Route) -> some View { switch route { case .goal: Text("Goals") } } } #Preview { ContentView() }This seems unexpected behaviour. If you ask AI the mental model is NavigationSplitViewColumn represents which column is currently visible for the user. That model would be wrong. Also i can't understand why a NavigationStack has to change the Binding? What am i missing here? Is my idea of the programmatic switch not supported? There are other ways to push from compact to your detail column again, but they all have trade-offs or run into other problems. I would appreciate any help here. AI has not understood this and only does surface level work arounds that fix nothing.
0
0
22
1d
Keyboard Toolbar Padding iOS26
When I create a SwiftUI toolbar item with placement of .keyboard on iOS 26, the item appears directly on top of and in contact with the keyboard. This does not look good visually nor does it match the behavior seen in Apple's apps, such as Reminders. Adding padding to the contents of the toolbar item only expands the size of the item but does not separate the capsule background of the item from the keyboard. How can I add vertical padding or spacing to separate the toolbar item capsule from the keyboard?
Topic: UI Frameworks SubTopic: SwiftUI
12
9
2.1k
1d
What pattern to use for an iPhone Tabview app
I have an iPhone tab view application that has not been designed for iPad, and I am aiming to add a left-hand bar that summarises some content and keeps visible what is normally a sheet. What pattern would work best for this? At present, I pass the view to another view with a navigation stack containing an arrangement view with the previous view and then the sidebar as a secondary view within it—would that be the appropriate approach?
Topic: UI Frameworks SubTopic: SwiftUI
3
0
392
1d
Best way to position game touch controls around the iPhone Duo hinge
For a full-screen game with a Metal/Unreal rendering view and a SwiftUI overlay for touch controls, what is the recommended way to keep interactive controls away from the hinge while still allowing the rendered game world to use the full display? Would you recommend querying ReservedRegion in the SwiftUI overlay while allowing the underlying render view to remain edge-to-edge? Also, should control placement respond continuously while the device is being folded, or primarily respond to layout/reserved-region changes once the pose changes?
Topic: UI Frameworks SubTopic: SwiftUI
1
0
83
2d
iPhone Duo: SwiftUI Layout Differs Between Simulator and Physical Device (Tab Bar Placement and Content Cropping)
Hi everyone, I'm experiencing a significant difference in SwiftUI layout behavior between the iPhone Duo simulator and a physical iPhone Duo. I've already adjusted my layout to work correctly in the simulator, but the same app behaves differently on the actual device. 1. Folded Simulator: The tab bar is positioned on the right side, as expected for iPhone Duo. The view respects the right-side layout, and scroll views extend naturally behind the tab bar, behaving as expected. Physical device: The tab bar appears at the bottom, like a regular iPhone, instead of on the right. The view is also cropped on the right side. 2. Unfolded Simulator: The tab bar and navigation view both appear correctly. Physical device: The tab bar remains at the bottom, even in landscape orientation, instead of using the expected Duo layout. The main content also starts from the bottom of the navigation view, resulting in an incorrect layout. The most confusing part is that the layout works correctly in the simulator but not on the physical device. Has anyone encountered this behavior on a physical iPhone Duo? Could this be related to the iOS version, SDK version, SwiftUI's automatic tab bar adaptation, or a device-specific bug? I'd appreciate any insights, especially from developers who have tested their SwiftUI apps on actual iPhone Duo hardware. Environment: Xcode version: 27.1 iOS SDK: 27.1 Physical device iOS version: 27.2 Thanks!
1
0
45
2d
Battery usage timeline graph shows incorrect time labels in macOS 27
Description: The time scale values on the battery usage curve in macOS 27 are displayed incorrectly. The screenshot timestamp is 14:39:11, October 20. Under the "Last 24 Hours" tab for Battery Level and Screen On Time charts, the timeline shows usage extending past 21:00 on October 20. This timestamp does not match the actual current time. It appears the timeline axis failed to shift correctly as time progresses. For comparison: a reference screenshot captured on macOS 26 at 09:30, August 8. Its battery usage timeline rendered correctly. The bottom time span covered August 7 to August 8, which is the expected and proper display behavior. This bug only exists in macOS 27’s battery usage chart. The older macOS 26 implementation works correctly. Device: MacBook Air M5 macOS version: macOS 27.2 RC
Topic: UI Frameworks SubTopic: SwiftUI
2
2
106
2d
iPhone Duo apps on the App Store
Will the App Store surface apps that are optimised for iPhone Duo, for example a badge, a filter or editorial placement? And is "optimised" decided just by building against 27.1, or by something else? Will App Store Connect require dedicated iPhone Duo screenshots for the outer and inner displays?
Topic: UI Frameworks SubTopic: SwiftUI
3
0
650
4d
iOS 27 reorderContainer: destination appearance changes ~0.9s after cross-collection drop
I'm seeing a delayed appearance change when moving a row between two collections using the new SwiftUI reordering APIs. The data updates immediately, but the dragged row retains its source appearance throughout settling, then abruptly switches to its destination appearance about 0.9 seconds after the move callback. Environment Xcode 27.0 (27A266a), macOS 26.7 (25G229) iOS Simulator 27.0 (24A434), iPhone 17 Pro Feedback: FB25054984 These observations are from the original simulator tests. I haven't established whether the same behavior occurs on a physical device or a newer runtime. Structure and observed behavior The hierarchy is a ScrollView containing a LazyVStack with sections. Each section uses ForEach(...).reorderable(collectionID:), under one .reorderContainer(for:in:move:). A dragContainer supplies transferable items, with DragConfiguration(allowMove: true). The same item has a compact appearance inside a group and a wider card appearance when standalone. Moving it between those collections updates membership, order, and the state driving its appearance synchronously in the move callback. Item IDs remain stable. Drag a compact grouped row into the standalone collection. Drop it between two standalone rows. The model and live presentation state update immediately. The dropped row keeps the source appearance during settling, then snaps to the destination appearance approximately 0.9 seconds later. Moving it back shows the same behavior. Different row heights also cause adjacent rows to step when the appearance changes. Measured delays in the application's synthetic-data sandbox were approximately 930 ms out and 921 ms back in. What I've tried Removing role-dependent content identity. Moving into an already populated destination collection. Giving source and destination rows equal occupied height. Using identity transitions. Bypassing the app's drawer modifier. None removed the late appearance switch. Equal occupied height removed the displacement of adjacent rows, but not the delayed visual change. A comparison using custom drop handling updated the appearance promptly, but did not preserve native insertion-position reordering. The feedback contains the original video, relevant logs and before/after frames. I also have a reduced standalone project that builds, but its manual drag-and-drop reproduction hasn't yet been verified; the timings above are from the application's sandbox, not that standalone sample. Questions Is retaining the source row's appearance until after settling expected when moving between collections? Is there a supported API or recommended row structure that lets the destination appearance and geometry participate in the settling animation? Has anyone reproduced this on iOS 27, or found it fixed in a newer runtime? I'd like to keep native reordering without timed refreshes, container identity resets, or private APIs.
0
0
60
5d
Inconsistent text scaling in web views on iPhone Duo
On iPad, text in a web view is always rendered at the same font size regardless of device orientation, sidebar presence, and window resizing. The text simply reflows according to the available space, as you would expect. In comparison, there appears to be a bug in iPhone Duo (or the Duo simulator) that causes web views to scale inconsistently depending on device orientation, presense/absence of the sidebar, and inner vs. outer screens. For example, showing and hiding the sidebar causes text in a web view to be rendered at different sizes rather than reflowing the text. Likewise, switching between portrait and landscape orientations causes text to be rendered at different sizes rather than reflowing. This occurs with the modern WebPage APIs introduced in iOS 26 as well as the older WKWebView APIs. Is this a known bug on the iPhone Duo? Is it just a simulator problem? Are there any recommended workarounds? Here's a quick example: import SwiftUI import WebKit struct ContentView: View { let webPage = WebPage() var body: some View { NavigationStack { WebView(webPage) } .task { webPage.load(html: """ <!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <title>Test page</title> </head> <body> <h1>This is a title</h1> <p>This is a paragraph.</p> </body> </html> """ ) } } }
Topic: UI Frameworks SubTopic: SwiftUI
0
0
274
6d
How do deal with NavigationSplitView not saving selection on iPhone
I have a detail view that has a @Binding var Thing, which is passed to it from the parent. It has TextFields that need to use that bound object's fields. // Using this to pass the selection around @Observable class AppSelection { var selectedThings:Set<Thing> = Set(); } struct ContentView: View { @State private var selectionStore = AppSelection(); var body: some View { NavigationSplitView { ... } content: { ...list that sets the selectionStore.selectedThings... } detail: { if !selectionStore.selectedThings.isEmpty { DetailView(thing:Binding( get: { selectionStore.selectedThings.first! }, // Crashes here set: { selectionStore.selectedThings = [$0] } )) .frame(maxHeight:.infinity, alignment:.top) } else { Text("Select a thing."); } } } } struct DetailView:View { @Binding var thing:Thing; var body:some View { TextField("Blah", $thing.name); TextField("Blerg", $thing.stuff); } }A crash happens when I navigate back from the DetailView in the line commented as such. I assume the NavigationSplitView is resetting the selection back to an empty state. Why the Binding given to the DetailView is even trying to get its value at that point is beyond me (so much weirdness in SwiftUI). I've taken so many different stabs at trying to make things work differently, but I just don't understand enough about SwiftUI. Like can I make the DetailView take an optional binding? If the Thing is nil, then all the TextFields complain that they require a non-optional binding. I don't even want to show the Detail view if nothing is selected (hence the "Select a thing.").
0
0
642
1w
Confirmation dialog anchor for a ToolbarOverflowMenu item
I have a destructive action exposed as a toolbar item, which might be collapsed into a ToolbarOverflowMenu. I'd present the delete confirmation as a confirmation dialog anchored to the button that triggered it. But when the action is inside the overflow menu, the menu item isn't a view I can anchor it to. What's the recommended pattern for the delete confirmation in that case? Is an alert the intended fallback, is there a supported way to anchor a confirmation dialog to a toolbar overflow item, or would you recommend a different approach altogether?
Topic: UI Frameworks SubTopic: SwiftUI
3
1
722
1w
SwiftUI Table on iPhone Duo
I am using the Table view in my app. On iPhone it only shows the first column, on iPad and Mac it shows all the columns. Since the Table view does not have an API to determine if the columns are shown, I am using self.horizontalSizeClass == .compact to find out if I need to show all content in the one column. Since the iPhone Duo is still an iPhone, even if it's unfolded, it only shows the one column, but the horizontalSizeClass is not compact. If we ignore that this all doesn't make any sense (why doesn't the Table just show the columns?!) my question is: how can I handle this case? Currently it just shows the first columns content.
Topic: UI Frameworks SubTopic: SwiftUI
8
0
1.4k
1w
TabView auto-dismisses fullScreenCover after tab list changes (crash with .zoom animation)
Summary A TabView with .tabViewStyle(.page) builds its tabs with ForEach; each tab presents a fullScreenCover(item:) from inside. Once the TabView is on screen, either of these breaks every later presentation: a tab is added or removed, or a tab's root view changes identity (Group { switch state } going from .loading to .loaded, with no tab added or removed). From then on each cover is dismissed by SwiftUI itself 15–70 ms after the present. With the standard transition it opens and closes once. With .navigationTransition(.zoom) the dismissal reaches UIKit while the cover is still animating in, and the app crashes: NSInternalInconsistencyException: Cannot morph from a view that is not in the hierarchy. Reproduces on iOS 26.0, 26.5 and 27.1 simulators and on devices on iOS 27.0.x. In our shipping app it is the top crash, ~2,000 events/day. How we got here The crash appeared when we adopted .navigationTransition(.zoom) for this cover. Every report is SheetBridge.dismiss/present → dismissViewControllerAnimated: → -[UIView(UIMorphableInternal) _morphPreviewFromCurrentState:…]. A second tap while the cover was still zooming in reproduced it; we guarded against that. Crashes continued. Disassembling UIKit showed that a dismissal during a zoom presentation preempts it and morphs from the presented view; if that view is not in the hierarchy, UIKit asserts instead of falling back. Any premature dismissal is enough. Our crash breadcrumbs showed every user navigating between tabs of a page-style TabView shortly before the crash, so we went looking for what dismisses a cover that was just presented. A lab with our topology (~1,700 automated presents) found the two triggers above. Both reproduce on iOS 26.0, 26.5 and 27.1, so the SwiftUI side is not new; the zoom transition is what makes it fatal. Steps to reproduce Run the PagedTabViewCoverRepro scheme (https://github.com/matheusmdutra03/PagedTabViewCoverRepro). The bottom tab bar selects the scenario; each screen explains the cause and shows the steps. "Page list changes": tap Add a tab, then tap any photo. "Page content changes": tap Reload tab content, then tap any photo. Expected The photo opens and stays until Close. Actual Zoom on: the app crashes with "Cannot morph from a view that is not in the hierarchy." Zoom off: the photo closes by itself about 1 s later. The on-screen counter shows "Dismissed by system". Why we think it happens The page-style TabView tracks the presentations made from its tabs, keyed by each tab's identity in the ForEach. Scenario 1 changes that identity directly: the tab list is diffed. Scenario 2 changes it indirectly. Group adds no view of its own, so the tab is whichever switch branch is active. When state flips, the branch changes type and SwiftUI sees a different view in that slot. For the TabView that is the same as removing the tab and inserting a new one. Either way the tracking is rebuilt and the tab's fullScreenCover loses the presentation it owns. Every present after that is treated as orphaned: SwiftUI dismisses it, presents a second copy, and dismisses that too (captured with method hooks on present/dismiss in the sample). With .zoom the final dismissal lands while the cover is still animating in and its view is not in the window yet; UIKit's zoom-out has no fallback for that and asserts. The broken state lives in the TabView subtree: recreating only the TabView clears it, and a cover attached outside the TabView is never affected. What fixed it in the sample Scenario 1: .id(tabs.map(\.title)) on the TabView, so a list change recreates the TabView instead of diffing it. 20/20 clean. Does not help scenario 2. Scenario 2: ZStack { switch state { … } } instead of Group { … } as the tab's root. ZStack is a real view, so the tab keeps its identity and the switch only changes its content. 20/20 clean. Does not help scenario 1. Both are app-side workarounds, one per trigger. A standard TabView, a paging ScrollView, or a cover attached outside the TabView never reproduce. Suggested fix Keep each tab's presentation bookkeeping bound to its ForEach identity across list diffs and root-identity changes, so a tab's fullScreenCover/sheet never loses the presentation it owns. If SwiftUI still has to dismiss a presentation it no longer tracks, do it without animation while the presented view is not in the window, so the UIKit zoom transition cannot assert. Results (iOS 27.1, 20 presents each) Scenario 1: 0 clean · 9 dismissed by system · 11 crashes. With .id(tabs): 20 clean. Scenario 2: 0 clean · 0 dismissed · 20 crashes. With ZStack: 20 clean. Attachments Evidence/ has crash logs (iOS 27.1 and 26.5), a screen recording, and the raw trial logs. The ZoomDismissCrashRepro scheme in the same project reproduces the UIKit assertion with five public-API calls and no SwiftUI.
Topic: UI Frameworks SubTopic: SwiftUI
2
0
122
1w
Duo not having different z index with overlay arrangement view style
When using ArrangementView with the overlay style, the Duo simulator does not appear to return a distinct z-index environment value, though it correctly displays z-index 0 and 1 on other iPhone simulators. I would like to use this value to determine whether the overlay is active. Currently, this does not seem possible. Is this behavior intended, or is it a bug? If intended, what is the recommended approach to determine if the Duo is displaying the arranged view over another arranged view? import SwiftUI struct ContentView: View { var body: some View { ArrangementView { Controls() } secondary: { Player() } .arrangementViewStyle(.overlay) } } struct Controls: View { @Environment(\.overlayArrangementZIndex) var zIndex var body: some View { Text("Controls Z:\(zIndex)") .frame(maxWidth: .infinity, alignment: .leading) } } struct Player: View { @Environment(\.overlayArrangementZIndex) var zIndex var body: some View { Text("Player Z:\(zIndex)") .frame(maxWidth: .infinity, alignment: .trailing) } } #Preview { ContentView() }
Topic: UI Frameworks SubTopic: SwiftUI
3
0
167
1w
Regression: AxisValueLabel anchor parameter ignores .topLeading on iOS 27
Hello Apple SwiftUI / Swift Charts Engineering Team, I am writing to report a layout regression regarding Swift Charts in iOS 27. The anchor property on AxisValueLabel has stopped honoring the .topLeading layout coordinate, whereas it functions perfectly in iOS 26. Bug Description: To prevent the first label on a bottom X-axis from clipping past the left screen edge, a .topLeading anchor is applied. In iOS 27, this specific anchor alignment is completely ignored. The chart falls back to a standard top-center alignment, causing the initial boundary label to clip off-screen. Core Code Snippet to Reproduce: struct XAxisAnchorBugView: View { let dates = [ Calendar.current.date(from: DateComponents(year: 2026, month: 10, day: 1))!, Calendar.current.date(from: DateComponents(year: 2026, month: 10, day: 2))! ] var body: some View { Chart(dates, id: .self) { date in LineMark(x: .value("Date", date), y: .value("Value", 100)) } .frame(height: 300) .padding() .chartXAxis { AxisMarks(preset: .aligned, position: .bottom, values: .stride(by: .day, count: 1)) { value in AxisTick() let currentAnchor: UnitPoint = { guard let currentDate = value.as(Date.self) else { return .top } // BUG: .topLeading layout anchor parameter is completely ignored on iOS 27 return (currentDate == dates.first) ? .topLeading : .top }() AxisValueLabel(format: .dateTime.month(.abbreviated).day(), anchor: currentAnchor) } } } } Steps to Reproduce: Render an X-axis with a .bottom position. Assign anchor: .topLeading strictly to the first axis element's label. Run on an iOS 26 simulator (the first label anchors its top-left corner correctly, preventing edge clipping). Run on an iOS 27 simulator (the .topLeading anchor is ignored, reverting to standard top-center alignment). Expected Behavior: AxisValueLabel should position its layout bounding box using the .topLeading anchor point when specified. Actual Behavior: The layout engine ignores the .topLeading parameter on iOS 27, causing the boundary text to shift left and clip. Attachments: I have attached Xcode Simulator screenshots demonstrating this regression: Best regards, Soumyajit Das
2
0
104
1w
Regression: AxisValueLabel multiLabelAlignment parameter ignored in iOS 27
Hello Apple SwiftUI / Swift Charts Engineering Team, I am writing to report a layout regression regarding Swift Charts in iOS 27. The multiLabelAlignment property on AxisValueLabel has stopped working as expected, whereas it functions perfectly in iOS 26. Bug Description: When configuring custom string values within AxisMarks using AxisValueLabel with multiLabelAlignment: .trailing, the alignment configuration is completely ignored on iOS 27. Labels fail to align text properly to the trailing edge, causing rendering layout issues for multi-line or custom text labels on the Y-axis. This exact same implementation compiles and aligns correctly on iOS 26. Code Snippet to Reproduce: swift struct YAxisAlignmentBugView: View { // data points to render the chart frame let data = [(date: Date(), revenue: 3000.0), (date: Date().addingTimeInterval(10000), revenue: 4000.0)] var body: some View { Chart(data, id: .date) { item in LineMark(x: .value("Date", item.date), y: .value("Revenue", item.revenue)) } .frame(height: 300) .padding() .chartYAxis { AxisMarks(preset: .aligned, position: .trailing, values: [12.0, 600.0, 3000.0, 6000.0]) { value in if let revenue = value.as(Double.self) { // BUG: multiLabelAlignment: .trailing is completely ignored on iOS 27 AxisValueLabel("y-(Int(revenue))", anchor: .leading, multiLabelAlignment: .trailing) } } } } } Steps to Reproduce: Render a Swift Chart containing a .chartYAxis configuration with position: .trailing. Pass a string directly using AxisValueLabel(customText, anchor: .leading, multiLabelAlignment: .trailing). Run the application on an iOS 26 simulator (text aligns properly to the trailing edge). Run the identical application code on an iOS 27 simulator. Expected Behavior: The text inside the AxisValueLabel should honor the multiLabelAlignment: .trailing parameter and align the text strings flush right. Actual Behavior: The multiLabelAlignment layout modifier is ignored on iOS 27, resulting in unexpected default left-alignment of the text strings. Attachments: I have attached screenshots from the Xcode Simulator demonstrating the regression: Please let me know if you need any further diagnostic details. Best regards, Soumyajit Das
2
0
78
1w
dismissalConfirmationDialog not working in iOS
It compiles for iOS but seems to be a no-op. Is this coming in a future beta? Or is there a way to hide the default back button when using the presentation + zoom navigationTransition APIs? I have a view that needs to show a confirmation on dismissal. I was previously doing this manually using a custom toolbar button + confirmationDialog modifier. But in iOS 27 I don't seem to be able to hide the navigation back button since I added the zoom navigationTransition API. This allows the user to tap the back button and lose changes. Not a great UX.
1
1
272
1w
Non-collapsing title
In the Photos app, the Collections title doesn't collapse into a small inline title when scrolling, unlike a standard inline large title display mode. How is this implemented?
Replies
0
Boosts
0
Views
1
Activity
46s
iOS 27 regression - minimized search item in top toolbar breaks its state
struct ContentView: View { @State var searchText: String = "" var body: some View { TabView { Tab { NavigationStack { List { Text("Hello!") Text("Hello!") Text("Hello!") Text("Hello!") Text("Hello!") Text("Hello!") } .navigationTitle("Have a title") .searchable(text: $searchText, placement: .toolbar) .searchToolbarBehavior(.minimize) .toolbar { DefaultToolbarItem(kind: .search, placement: .topBarTrailing) } } } } } } In iOS 26, this worked no problem. In iOS 27, this leaves the search bar either unable to collapse (when pressing the close button) or in a broken state where it cannot be opened again.
Topic: UI Frameworks SubTopic: SwiftUI
Replies
8
Boosts
11
Views
1.7k
Activity
15h
NavigationSplitView Binding to NavigationSplitViewColumn reset with every NavigationStack path change
I try to create a Navigation that works on iPhone, iPhone Duo and iPad. NavigationSplitView collapses for compact form factors and makes iPhone Duo support much simpler. The Problem is the semantic of the collapse. Switch from detail to sidebar on compact is not a 'back' action in my case. It should have my choosen Icon and has a meaning. So i wanted to control this using the NavigationSpliViewColumn Binding. This does work forward and backward as long as no NavigationStack was used before. But it stops working when you return to the detail root from a Navigation-Action. I left the Backbutton visible so you can test, that it continues to work, when no Navigation-Action preceeded the switch. Here is my Code: import SwiftUI @Observable final class Compass { var path: [Route] init() { self.path = [] } } enum Route: Hashable { case goal } struct ContentView: View { @Environment(\.horizontalSizeClass) private var hsize @State private var compass: Compass = Compass() @State var column: NavigationSplitViewColumn = .detail var body: some View { NavigationSplitView(preferredCompactColumn: $column) { OverviewScreen(column: $column) } detail: { TodayScreen() .toolbar { ToolbarItem(placement: .topBarLeading) { Button("overview", systemImage: "calendar") { self.column = .sidebar } } } } .environment(compass) .onChange(of: column) { old, new in print("column:", old, "→", new) } } } struct OverviewScreen: View { @Binding var column: NavigationSplitViewColumn @Environment(Compass.self) var compass var body: some View { @Bindable var compass = self.compass ScrollView { Text("Overview") .font(.largeTitle) .fontWeight(.heavy) Button("Switch") { self.column = .detail } } } } struct TodayScreen: View { @Environment(Compass.self) var compass var body: some View { @Bindable var compass = self.compass NavigationStack(path: $compass.path) { ScrollView { Text("Today") .font(.largeTitle) .fontWeight(.heavy) Button("Goals programtically", systemImage: "flag.fill") { self.compass.path = [.goal] } NavigationLink(value: Route.goal) { Label("Goal Link", systemImage: "flag.fill") } } .navigationDestination(for: Route.self, destination: self.screen) } } @ContentBuilder func screen(for route: Route) -> some View { switch route { case .goal: Text("Goals") } } } #Preview { ContentView() }This seems unexpected behaviour. If you ask AI the mental model is NavigationSplitViewColumn represents which column is currently visible for the user. That model would be wrong. Also i can't understand why a NavigationStack has to change the Binding? What am i missing here? Is my idea of the programmatic switch not supported? There are other ways to push from compact to your detail column again, but they all have trade-offs or run into other problems. I would appreciate any help here. AI has not understood this and only does surface level work arounds that fix nothing.
Replies
0
Boosts
0
Views
22
Activity
1d
Keyboard Toolbar Padding iOS26
When I create a SwiftUI toolbar item with placement of .keyboard on iOS 26, the item appears directly on top of and in contact with the keyboard. This does not look good visually nor does it match the behavior seen in Apple's apps, such as Reminders. Adding padding to the contents of the toolbar item only expands the size of the item but does not separate the capsule background of the item from the keyboard. How can I add vertical padding or spacing to separate the toolbar item capsule from the keyboard?
Topic: UI Frameworks SubTopic: SwiftUI
Replies
12
Boosts
9
Views
2.1k
Activity
1d
What pattern to use for an iPhone Tabview app
I have an iPhone tab view application that has not been designed for iPad, and I am aiming to add a left-hand bar that summarises some content and keeps visible what is normally a sheet. What pattern would work best for this? At present, I pass the view to another view with a navigation stack containing an arrangement view with the previous view and then the sidebar as a secondary view within it—would that be the appropriate approach?
Topic: UI Frameworks SubTopic: SwiftUI
Replies
3
Boosts
0
Views
392
Activity
1d
Best way to position game touch controls around the iPhone Duo hinge
For a full-screen game with a Metal/Unreal rendering view and a SwiftUI overlay for touch controls, what is the recommended way to keep interactive controls away from the hinge while still allowing the rendered game world to use the full display? Would you recommend querying ReservedRegion in the SwiftUI overlay while allowing the underlying render view to remain edge-to-edge? Also, should control placement respond continuously while the device is being folded, or primarily respond to layout/reserved-region changes once the pose changes?
Topic: UI Frameworks SubTopic: SwiftUI
Replies
1
Boosts
0
Views
83
Activity
2d
iPhone Duo: SwiftUI Layout Differs Between Simulator and Physical Device (Tab Bar Placement and Content Cropping)
Hi everyone, I'm experiencing a significant difference in SwiftUI layout behavior between the iPhone Duo simulator and a physical iPhone Duo. I've already adjusted my layout to work correctly in the simulator, but the same app behaves differently on the actual device. 1. Folded Simulator: The tab bar is positioned on the right side, as expected for iPhone Duo. The view respects the right-side layout, and scroll views extend naturally behind the tab bar, behaving as expected. Physical device: The tab bar appears at the bottom, like a regular iPhone, instead of on the right. The view is also cropped on the right side. 2. Unfolded Simulator: The tab bar and navigation view both appear correctly. Physical device: The tab bar remains at the bottom, even in landscape orientation, instead of using the expected Duo layout. The main content also starts from the bottom of the navigation view, resulting in an incorrect layout. The most confusing part is that the layout works correctly in the simulator but not on the physical device. Has anyone encountered this behavior on a physical iPhone Duo? Could this be related to the iOS version, SDK version, SwiftUI's automatic tab bar adaptation, or a device-specific bug? I'd appreciate any insights, especially from developers who have tested their SwiftUI apps on actual iPhone Duo hardware. Environment: Xcode version: 27.1 iOS SDK: 27.1 Physical device iOS version: 27.2 Thanks!
Replies
1
Boosts
0
Views
45
Activity
2d
Battery usage timeline graph shows incorrect time labels in macOS 27
Description: The time scale values on the battery usage curve in macOS 27 are displayed incorrectly. The screenshot timestamp is 14:39:11, October 20. Under the "Last 24 Hours" tab for Battery Level and Screen On Time charts, the timeline shows usage extending past 21:00 on October 20. This timestamp does not match the actual current time. It appears the timeline axis failed to shift correctly as time progresses. For comparison: a reference screenshot captured on macOS 26 at 09:30, August 8. Its battery usage timeline rendered correctly. The bottom time span covered August 7 to August 8, which is the expected and proper display behavior. This bug only exists in macOS 27’s battery usage chart. The older macOS 26 implementation works correctly. Device: MacBook Air M5 macOS version: macOS 27.2 RC
Topic: UI Frameworks SubTopic: SwiftUI
Replies
2
Boosts
2
Views
106
Activity
2d
iPhone Duo apps on the App Store
Will the App Store surface apps that are optimised for iPhone Duo, for example a badge, a filter or editorial placement? And is "optimised" decided just by building against 27.1, or by something else? Will App Store Connect require dedicated iPhone Duo screenshots for the outer and inner displays?
Topic: UI Frameworks SubTopic: SwiftUI
Replies
3
Boosts
0
Views
650
Activity
4d
iOS 27 reorderContainer: destination appearance changes ~0.9s after cross-collection drop
I'm seeing a delayed appearance change when moving a row between two collections using the new SwiftUI reordering APIs. The data updates immediately, but the dragged row retains its source appearance throughout settling, then abruptly switches to its destination appearance about 0.9 seconds after the move callback. Environment Xcode 27.0 (27A266a), macOS 26.7 (25G229) iOS Simulator 27.0 (24A434), iPhone 17 Pro Feedback: FB25054984 These observations are from the original simulator tests. I haven't established whether the same behavior occurs on a physical device or a newer runtime. Structure and observed behavior The hierarchy is a ScrollView containing a LazyVStack with sections. Each section uses ForEach(...).reorderable(collectionID:), under one .reorderContainer(for:in:move:). A dragContainer supplies transferable items, with DragConfiguration(allowMove: true). The same item has a compact appearance inside a group and a wider card appearance when standalone. Moving it between those collections updates membership, order, and the state driving its appearance synchronously in the move callback. Item IDs remain stable. Drag a compact grouped row into the standalone collection. Drop it between two standalone rows. The model and live presentation state update immediately. The dropped row keeps the source appearance during settling, then snaps to the destination appearance approximately 0.9 seconds later. Moving it back shows the same behavior. Different row heights also cause adjacent rows to step when the appearance changes. Measured delays in the application's synthetic-data sandbox were approximately 930 ms out and 921 ms back in. What I've tried Removing role-dependent content identity. Moving into an already populated destination collection. Giving source and destination rows equal occupied height. Using identity transitions. Bypassing the app's drawer modifier. None removed the late appearance switch. Equal occupied height removed the displacement of adjacent rows, but not the delayed visual change. A comparison using custom drop handling updated the appearance promptly, but did not preserve native insertion-position reordering. The feedback contains the original video, relevant logs and before/after frames. I also have a reduced standalone project that builds, but its manual drag-and-drop reproduction hasn't yet been verified; the timings above are from the application's sandbox, not that standalone sample. Questions Is retaining the source row's appearance until after settling expected when moving between collections? Is there a supported API or recommended row structure that lets the destination appearance and geometry participate in the settling animation? Has anyone reproduced this on iOS 27, or found it fixed in a newer runtime? I'd like to keep native reordering without timed refreshes, container identity resets, or private APIs.
Replies
0
Boosts
0
Views
60
Activity
5d
Inconsistent text scaling in web views on iPhone Duo
On iPad, text in a web view is always rendered at the same font size regardless of device orientation, sidebar presence, and window resizing. The text simply reflows according to the available space, as you would expect. In comparison, there appears to be a bug in iPhone Duo (or the Duo simulator) that causes web views to scale inconsistently depending on device orientation, presense/absence of the sidebar, and inner vs. outer screens. For example, showing and hiding the sidebar causes text in a web view to be rendered at different sizes rather than reflowing the text. Likewise, switching between portrait and landscape orientations causes text to be rendered at different sizes rather than reflowing. This occurs with the modern WebPage APIs introduced in iOS 26 as well as the older WKWebView APIs. Is this a known bug on the iPhone Duo? Is it just a simulator problem? Are there any recommended workarounds? Here's a quick example: import SwiftUI import WebKit struct ContentView: View { let webPage = WebPage() var body: some View { NavigationStack { WebView(webPage) } .task { webPage.load(html: """ <!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <title>Test page</title> </head> <body> <h1>This is a title</h1> <p>This is a paragraph.</p> </body> </html> """ ) } } }
Topic: UI Frameworks SubTopic: SwiftUI
Replies
0
Boosts
0
Views
274
Activity
6d
How do deal with NavigationSplitView not saving selection on iPhone
I have a detail view that has a @Binding var Thing, which is passed to it from the parent. It has TextFields that need to use that bound object's fields. // Using this to pass the selection around @Observable class AppSelection { var selectedThings:Set<Thing> = Set(); } struct ContentView: View { @State private var selectionStore = AppSelection(); var body: some View { NavigationSplitView { ... } content: { ...list that sets the selectionStore.selectedThings... } detail: { if !selectionStore.selectedThings.isEmpty { DetailView(thing:Binding( get: { selectionStore.selectedThings.first! }, // Crashes here set: { selectionStore.selectedThings = [$0] } )) .frame(maxHeight:.infinity, alignment:.top) } else { Text("Select a thing."); } } } } struct DetailView:View { @Binding var thing:Thing; var body:some View { TextField("Blah", $thing.name); TextField("Blerg", $thing.stuff); } }A crash happens when I navigate back from the DetailView in the line commented as such. I assume the NavigationSplitView is resetting the selection back to an empty state. Why the Binding given to the DetailView is even trying to get its value at that point is beyond me (so much weirdness in SwiftUI). I've taken so many different stabs at trying to make things work differently, but I just don't understand enough about SwiftUI. Like can I make the DetailView take an optional binding? If the Thing is nil, then all the TextFields complain that they require a non-optional binding. I don't even want to show the Detail view if nothing is selected (hence the "Select a thing.").
Replies
0
Boosts
0
Views
642
Activity
1w
Confirmation dialog anchor for a ToolbarOverflowMenu item
I have a destructive action exposed as a toolbar item, which might be collapsed into a ToolbarOverflowMenu. I'd present the delete confirmation as a confirmation dialog anchored to the button that triggered it. But when the action is inside the overflow menu, the menu item isn't a view I can anchor it to. What's the recommended pattern for the delete confirmation in that case? Is an alert the intended fallback, is there a supported way to anchor a confirmation dialog to a toolbar overflow item, or would you recommend a different approach altogether?
Topic: UI Frameworks SubTopic: SwiftUI
Replies
3
Boosts
1
Views
722
Activity
1w
SwiftUI Table on iPhone Duo
I am using the Table view in my app. On iPhone it only shows the first column, on iPad and Mac it shows all the columns. Since the Table view does not have an API to determine if the columns are shown, I am using self.horizontalSizeClass == .compact to find out if I need to show all content in the one column. Since the iPhone Duo is still an iPhone, even if it's unfolded, it only shows the one column, but the horizontalSizeClass is not compact. If we ignore that this all doesn't make any sense (why doesn't the Table just show the columns?!) my question is: how can I handle this case? Currently it just shows the first columns content.
Topic: UI Frameworks SubTopic: SwiftUI
Replies
8
Boosts
0
Views
1.4k
Activity
1w
TabView auto-dismisses fullScreenCover after tab list changes (crash with .zoom animation)
Summary A TabView with .tabViewStyle(.page) builds its tabs with ForEach; each tab presents a fullScreenCover(item:) from inside. Once the TabView is on screen, either of these breaks every later presentation: a tab is added or removed, or a tab's root view changes identity (Group { switch state } going from .loading to .loaded, with no tab added or removed). From then on each cover is dismissed by SwiftUI itself 15–70 ms after the present. With the standard transition it opens and closes once. With .navigationTransition(.zoom) the dismissal reaches UIKit while the cover is still animating in, and the app crashes: NSInternalInconsistencyException: Cannot morph from a view that is not in the hierarchy. Reproduces on iOS 26.0, 26.5 and 27.1 simulators and on devices on iOS 27.0.x. In our shipping app it is the top crash, ~2,000 events/day. How we got here The crash appeared when we adopted .navigationTransition(.zoom) for this cover. Every report is SheetBridge.dismiss/present → dismissViewControllerAnimated: → -[UIView(UIMorphableInternal) _morphPreviewFromCurrentState:…]. A second tap while the cover was still zooming in reproduced it; we guarded against that. Crashes continued. Disassembling UIKit showed that a dismissal during a zoom presentation preempts it and morphs from the presented view; if that view is not in the hierarchy, UIKit asserts instead of falling back. Any premature dismissal is enough. Our crash breadcrumbs showed every user navigating between tabs of a page-style TabView shortly before the crash, so we went looking for what dismisses a cover that was just presented. A lab with our topology (~1,700 automated presents) found the two triggers above. Both reproduce on iOS 26.0, 26.5 and 27.1, so the SwiftUI side is not new; the zoom transition is what makes it fatal. Steps to reproduce Run the PagedTabViewCoverRepro scheme (https://github.com/matheusmdutra03/PagedTabViewCoverRepro). The bottom tab bar selects the scenario; each screen explains the cause and shows the steps. "Page list changes": tap Add a tab, then tap any photo. "Page content changes": tap Reload tab content, then tap any photo. Expected The photo opens and stays until Close. Actual Zoom on: the app crashes with "Cannot morph from a view that is not in the hierarchy." Zoom off: the photo closes by itself about 1 s later. The on-screen counter shows "Dismissed by system". Why we think it happens The page-style TabView tracks the presentations made from its tabs, keyed by each tab's identity in the ForEach. Scenario 1 changes that identity directly: the tab list is diffed. Scenario 2 changes it indirectly. Group adds no view of its own, so the tab is whichever switch branch is active. When state flips, the branch changes type and SwiftUI sees a different view in that slot. For the TabView that is the same as removing the tab and inserting a new one. Either way the tracking is rebuilt and the tab's fullScreenCover loses the presentation it owns. Every present after that is treated as orphaned: SwiftUI dismisses it, presents a second copy, and dismisses that too (captured with method hooks on present/dismiss in the sample). With .zoom the final dismissal lands while the cover is still animating in and its view is not in the window yet; UIKit's zoom-out has no fallback for that and asserts. The broken state lives in the TabView subtree: recreating only the TabView clears it, and a cover attached outside the TabView is never affected. What fixed it in the sample Scenario 1: .id(tabs.map(\.title)) on the TabView, so a list change recreates the TabView instead of diffing it. 20/20 clean. Does not help scenario 2. Scenario 2: ZStack { switch state { … } } instead of Group { … } as the tab's root. ZStack is a real view, so the tab keeps its identity and the switch only changes its content. 20/20 clean. Does not help scenario 1. Both are app-side workarounds, one per trigger. A standard TabView, a paging ScrollView, or a cover attached outside the TabView never reproduce. Suggested fix Keep each tab's presentation bookkeeping bound to its ForEach identity across list diffs and root-identity changes, so a tab's fullScreenCover/sheet never loses the presentation it owns. If SwiftUI still has to dismiss a presentation it no longer tracks, do it without animation while the presented view is not in the window, so the UIKit zoom transition cannot assert. Results (iOS 27.1, 20 presents each) Scenario 1: 0 clean · 9 dismissed by system · 11 crashes. With .id(tabs): 20 clean. Scenario 2: 0 clean · 0 dismissed · 20 crashes. With ZStack: 20 clean. Attachments Evidence/ has crash logs (iOS 27.1 and 26.5), a screen recording, and the raw trial logs. The ZoomDismissCrashRepro scheme in the same project reproduces the UIKit assertion with five public-API calls and no SwiftUI.
Topic: UI Frameworks SubTopic: SwiftUI
Replies
2
Boosts
0
Views
122
Activity
1w
Duo not having different z index with overlay arrangement view style
When using ArrangementView with the overlay style, the Duo simulator does not appear to return a distinct z-index environment value, though it correctly displays z-index 0 and 1 on other iPhone simulators. I would like to use this value to determine whether the overlay is active. Currently, this does not seem possible. Is this behavior intended, or is it a bug? If intended, what is the recommended approach to determine if the Duo is displaying the arranged view over another arranged view? import SwiftUI struct ContentView: View { var body: some View { ArrangementView { Controls() } secondary: { Player() } .arrangementViewStyle(.overlay) } } struct Controls: View { @Environment(\.overlayArrangementZIndex) var zIndex var body: some View { Text("Controls Z:\(zIndex)") .frame(maxWidth: .infinity, alignment: .leading) } } struct Player: View { @Environment(\.overlayArrangementZIndex) var zIndex var body: some View { Text("Player Z:\(zIndex)") .frame(maxWidth: .infinity, alignment: .trailing) } } #Preview { ContentView() }
Topic: UI Frameworks SubTopic: SwiftUI
Replies
3
Boosts
0
Views
167
Activity
1w
Regression: AxisValueLabel anchor parameter ignores .topLeading on iOS 27
Hello Apple SwiftUI / Swift Charts Engineering Team, I am writing to report a layout regression regarding Swift Charts in iOS 27. The anchor property on AxisValueLabel has stopped honoring the .topLeading layout coordinate, whereas it functions perfectly in iOS 26. Bug Description: To prevent the first label on a bottom X-axis from clipping past the left screen edge, a .topLeading anchor is applied. In iOS 27, this specific anchor alignment is completely ignored. The chart falls back to a standard top-center alignment, causing the initial boundary label to clip off-screen. Core Code Snippet to Reproduce: struct XAxisAnchorBugView: View { let dates = [ Calendar.current.date(from: DateComponents(year: 2026, month: 10, day: 1))!, Calendar.current.date(from: DateComponents(year: 2026, month: 10, day: 2))! ] var body: some View { Chart(dates, id: .self) { date in LineMark(x: .value("Date", date), y: .value("Value", 100)) } .frame(height: 300) .padding() .chartXAxis { AxisMarks(preset: .aligned, position: .bottom, values: .stride(by: .day, count: 1)) { value in AxisTick() let currentAnchor: UnitPoint = { guard let currentDate = value.as(Date.self) else { return .top } // BUG: .topLeading layout anchor parameter is completely ignored on iOS 27 return (currentDate == dates.first) ? .topLeading : .top }() AxisValueLabel(format: .dateTime.month(.abbreviated).day(), anchor: currentAnchor) } } } } Steps to Reproduce: Render an X-axis with a .bottom position. Assign anchor: .topLeading strictly to the first axis element's label. Run on an iOS 26 simulator (the first label anchors its top-left corner correctly, preventing edge clipping). Run on an iOS 27 simulator (the .topLeading anchor is ignored, reverting to standard top-center alignment). Expected Behavior: AxisValueLabel should position its layout bounding box using the .topLeading anchor point when specified. Actual Behavior: The layout engine ignores the .topLeading parameter on iOS 27, causing the boundary text to shift left and clip. Attachments: I have attached Xcode Simulator screenshots demonstrating this regression: Best regards, Soumyajit Das
Replies
2
Boosts
0
Views
104
Activity
1w
Regression: AxisValueLabel multiLabelAlignment parameter ignored in iOS 27
Hello Apple SwiftUI / Swift Charts Engineering Team, I am writing to report a layout regression regarding Swift Charts in iOS 27. The multiLabelAlignment property on AxisValueLabel has stopped working as expected, whereas it functions perfectly in iOS 26. Bug Description: When configuring custom string values within AxisMarks using AxisValueLabel with multiLabelAlignment: .trailing, the alignment configuration is completely ignored on iOS 27. Labels fail to align text properly to the trailing edge, causing rendering layout issues for multi-line or custom text labels on the Y-axis. This exact same implementation compiles and aligns correctly on iOS 26. Code Snippet to Reproduce: swift struct YAxisAlignmentBugView: View { // data points to render the chart frame let data = [(date: Date(), revenue: 3000.0), (date: Date().addingTimeInterval(10000), revenue: 4000.0)] var body: some View { Chart(data, id: .date) { item in LineMark(x: .value("Date", item.date), y: .value("Revenue", item.revenue)) } .frame(height: 300) .padding() .chartYAxis { AxisMarks(preset: .aligned, position: .trailing, values: [12.0, 600.0, 3000.0, 6000.0]) { value in if let revenue = value.as(Double.self) { // BUG: multiLabelAlignment: .trailing is completely ignored on iOS 27 AxisValueLabel("y-(Int(revenue))", anchor: .leading, multiLabelAlignment: .trailing) } } } } } Steps to Reproduce: Render a Swift Chart containing a .chartYAxis configuration with position: .trailing. Pass a string directly using AxisValueLabel(customText, anchor: .leading, multiLabelAlignment: .trailing). Run the application on an iOS 26 simulator (text aligns properly to the trailing edge). Run the identical application code on an iOS 27 simulator. Expected Behavior: The text inside the AxisValueLabel should honor the multiLabelAlignment: .trailing parameter and align the text strings flush right. Actual Behavior: The multiLabelAlignment layout modifier is ignored on iOS 27, resulting in unexpected default left-alignment of the text strings. Attachments: I have attached screenshots from the Xcode Simulator demonstrating the regression: Please let me know if you need any further diagnostic details. Best regards, Soumyajit Das
Replies
2
Boosts
0
Views
78
Activity
1w
dismissalConfirmationDialog not working in iOS
It compiles for iOS but seems to be a no-op. Is this coming in a future beta? Or is there a way to hide the default back button when using the presentation + zoom navigationTransition APIs? I have a view that needs to show a confirmation on dismissal. I was previously doing this manually using a custom toolbar button + confirmationDialog modifier. But in iOS 27 I don't seem to be able to hide the navigation back button since I added the zoom navigationTransition API. This allows the user to tap the back button and lose changes. Not a great UX.
Replies
1
Boosts
1
Views
272
Activity
1w