Explore the various UI frameworks available for building app interfaces. Discuss the use cases for different frameworks, share best practices, and get help with specific framework-related questions.

All subtopics
Posts under UI Frameworks topic

Post

Replies

Boosts

Views

Activity

A Summary of the iPhone Duo Group Lab
Group Labs are a unique opportunity for the community to submit questions directly to a panel of Apple engineers and designers. Here are the highlights from the iPhone Duo Group Labs: How should apps preserve navigation and UI state when switching between the inner and outer displays? Treat display transitions as size-class and trait changes, not a scene disconnect or app termination; your process stays alive. For more information, see Prepare your app for iPhone Duo. For state that must survive a scene disconnect/reconnect, implement stateRestorationActivity(for:) to save an NSUserActivity Restoring your app's state. Do multiple instances of the same app on iPhone Duo share UserDefaults/@AppStorage state? Multiple instances of your app's UI on iPhone Duo behave similarly to multi-window support on iPadOS. To learn more, see Leverage multiple displays and scenes on iPhone Duo. Both UserDefaults and AppStorage are app-wide, not per-window, stores. If a full-screen app on the inner display is closed, does it move to the outer display or get backgrounded? iPhone Duo honors UIRequiresFullScreen and apps adapt in place as the device opens and closes rather than backgrounding. To learn more, watch Prepare your app for iPhone Duo. How should apps preserve state — text input, scroll position, video playback, camera sessions — during hinge angle transitions? For example, when a LazyVGrid's column count changes because the device folds, does SwiftUI preserve scroll position automatically, or should you use scrollPosition(id:)? The system generally preserves text input and scroll position automatically since hinge angle changes are represented as size-class and trait updates, not a scene disconnect or app termination. This applies even to cases like a LazyVGrid column-count change triggered by opening or closing the device — apps typically don't need to manually manage scroll position with scrollPosition(id:anchor:) for this transition. For more info, see Prepare your app for iPhone Duo. How can apps preserve what someone is doing when switching displays or folding/unfolding? Treat this as a resize/trait-change event, not app teardown — your process keeps running as size classes change. See Prepare your app for iPhone Duo to learn more. For scenes that actually disconnect and reconnect, implement stateRestorationActivity(for:) to save an NSUserActivity Restoring your app's state. How does actively playing video behave through the hinge angle animation? The system generally preserves video playback and player position automatically since hinge angle changes are represented as size-class and trait updates, not a scene disconnect or app termination. AVKit will scale and resize the video automatically. If a user folds or unfolds the device mid-checkout, what does the system preserve automatically, and what should the app manage itself to avoid lost input or duplicate requests? When someone opens or closes an iPhone Duo, the system represents this as a size-class and trait collection change, not a scene disconnect or app teardown, so in-memory state like input fields typically persists automatically since the app’s process keeps running. For more info, see Prepare your app for iPhone Duo. How should apps handle the keyboard and text input when the device folds or unfolds while typing? As iPhone Duo folds or unfolds, the available screen geometry and framing change. Ensure your app adopts standard layout controls, containers, and size classes to handle resizability gracefully across all poses. When a text field becomes first responder, the system automatically shows the keyboard and binds its input to the text field. Because the appearance of the keyboard has the potential to obscure portions of your user interface, you should update your interface as needed to ensure that the text field being edited remains visible. Use keyboard notifications such as keyboardWillShowNotification, keyboardWillHideNotification, and keyboardWillChangeFrameNotification to detect the appearance and disappearance of the keyboard and to make necessary changes to your interface layout. To learn more, see UITextField. If someone is typing and closes iPhone Duo, does the keyboard/editing session survive the hinge transition, or does it get a new scene? When a user types and closes iPhone Duo, the active editing session and keyboard do not get a completely new scene. Instead, the app undergoes a dynamic resizing and transitions from the inner display to the compact outer display, maintaining the existing scene and application state. For more info, watch Prepare your app for iPhone Duo.
16
0
933
3d
Can a Notes note be dragged into another app on iPhone Duo?
I’m adding drag-and-drop support to my app for multitasking on iPhone Duo. My app supports text/note content. Currently, a user can move content from Apple Notes into my app using Share or Copy/Paste. ** Questions** Can a note from the Notes app be dragged directly into another app during multitasking, similar to dragging a photo? If so, what content type does Notes provide through the drag-and-drop session? For example, is the note exposed as plain text (public.plain-text / UTType.plainText), rich text, or another transferable type? My goal is for the user to drag a note from Notes into my app and have it behave essentially like Copy → Paste, without requiring the Share sheet. Thank you.
0
0
31
6h
SwiftUI Document API Duplicate Function hangs on macOS 27
In a macOS 27 app using DocumentGroup(editor:makeDocument:) with a type conforming to the new Document protocol, choosing File › Duplicate hangs the app permanently (0% CPU, spinning beach ball, must force quit). The main thread is blocked in URLPlatformDocument.read(from:ofType:) waiting on a dispatch semaphore. That synchronous NSDocument read path is reached from NSDocumentController.duplicateDocumentWithContentsOfURL(:copying:displayName:) → makeDocumentForURL(:withContentsOf:ofType:) → NSDocument.init(for:withContentsOf:ofType:). The work the semaphore waits for never runs: the app's makeDocument closure is never called. The SDK declares makeDocument and ReadableDocument.apply(snapshot:previous:) as @MainActor, so blocking the main thread while waiting for them can never complete. This reproduces with Apple's unmodified sample code project "Building a Document-Based App with SwiftUI" (no code or project changes; only a signing team set). Our own app, which uses a custom DocumentReader/DocumentWriter with Source/Destination == URL, hangs with the identical stack. Has anyone found any workaround? Filed Feedback FB24949862
Topic: UI Frameworks SubTopic: SwiftUI
0
0
27
7h
sidebarAdaptable Design Problem
This is what Apple's Destination Video Sample App looks like on iPhone Duo built with SDK 27.1 beta. Two things: Items that should not appear in the tab bar appear. There is no sidebar for iPhone Duo. So my problem is: is this a bug or a design on purpose? Will sidebarAdaptable gets a sidebar on iPhone Duo? Or at least, how to hide these things that should only appear in the sidebar? The sample app uses .defaultVisibility(, for:) and .hidden() but obviously none of these takes effect.
Topic: UI Frameworks SubTopic: SwiftUI
1
1
170
7h
How to check for multiple scene support on iPhone Duo?
I have an iOS app that supports multiple scenes on the iPad, and which has an "Open in Another Window" feature which creates a new window scene. I would like to bring this feature to the iPhone Duo. On the iPhone Duo, of course, creating new windows is only supported when the device is open; when it is closed, creating new windows does not work. (If you try, an error is thrown.) Until now, the way I have checked whether my "Open in Another Window" feature should be available is to check to see if UIApplication.shared.supportsMultipleScenes is true. This has always returned false for previous iPhones and true for iPads. Unfortunately, however, this does not work as expected on the iPhone Duo. On the Duo, I would expect supportsMultipleScenes to return true when the device is open, but false when it is closed. This is not the case: it returns true for all poses. (Filed as #FB24948411 as this doesn't seem right to me.) So it does not help me decide whether the feature should be available. UIWindowScene.ActivationAction does work as expected when used in a menu, with the action auto-hiding when the Duo is in the closed pose. In my app, though, I need more than just an auto-hiding menu item; I need to check whether creating a new window is currently possible for certain UI availability decisions. What, then, is the correct way of checking this, if it's not with supportsMultipleScenes? Given that UIWindowScene.ActivationAction is able to hide itself, I assume there is some better way of checking that I have missed.
Topic: UI Frameworks SubTopic: UIKit Tags:
0
0
36
9h
Supported way to put an iPhone Duo simulator into the unfolded state programmatically
The Duo simulator boots showing only the outer display: the window is fixed at 382×644 pt and our layout classifier always reports the compact stack mode. We measured this on two separate clean boots (shutdown, erase, boot). xcrun simctl help lists no subcommand for folding, posture, or selecting the inner display — we read the full list. xcrun simctl io screenshot does reveal a second display (LCD-1, 2007×2853 px, aspect 0.70, close to the 669×951 inner portrait size). Unfolding manually in the Simulator UI works and the app then renders the two-column layout correctly, but we could not find a programmatic equivalent. Is there a supported way to unfold a Duo simulator from the command line or from XCTest?
Topic: UI Frameworks SubTopic: SwiftUI
3
3
702
1d
Enable iPhone Duo Upside Down Orientation
Ever since the iPhone X, upside-down orientation on the iPhone has been disabled by design. I haven't found any official documentation explaining why, but my guess is it has to do with Face ID and the top notch. However, now that the iPhone Duo has no Face ID or notch—and includes reserved occlusion regions—why not enable upside-down rotation? As of iOS 27.1, it remains disabled. Leaving it turned off only confuses users, making them think their favorite apps are frozen when they won't rotate.
Topic: UI Frameworks SubTopic: SwiftUI
1
1
308
1d
iPhone Duo and the Safe-Area
I took a screenshot of the Safety Area's and Occlusions on the iPhone Duo outer display. The article Designing for iPhone Duo tells us to... Consider using the full display width for interfaces where bars aren’t necessary. Some layouts can span the full display, which works well for visual, immersive interfaces that don’t scroll, as long as nothing conflicts with the Dynamic Island or the status bar. Calculator, for example, occupies the full width of the display. You can also combine both approaches, letting a background image or header span the full width while scrollable content stays inset. The Graphics Content can easily take up the full space which can be achieved by ignoring the safe area (.ignoresSafeArea()). And knowing the iPhone Duo there is no occlusion so I can also ignore the safe area for the interactable content. However we now are entering an awkward state. Because now I need to make decisions based on a specific device. Knowing the iPhone Duo I can ignore horizontal safe area and expand to full width because there is no occlusions here, but ignoring the safe-area may result in unexpected behavior on other (future) devices which then requires me to use code that specificly targets certain devices. I wished SwiftUI had something that I could safely expand the interactable content the full width.
Topic: UI Frameworks SubTopic: SwiftUI
2
0
105
1d
iOS 27: UIApplication.shared.open fail for relative URL values that resolve to valid https URLs
A URL created with URL(string:relativeTo:) that used to work in iOS26 and below with UIApplication.shared.open stopped working in iOS27, the app has not been built yet with iOS27 SDK. Have anyone seen this issue, all the links work perfectly in iOS26 and below. We found a solution to use .absoluteURL but still want to check with the community, I havent seen any mention of this this that it will break try the below sample code import UIKit struct RelativeURLReproView: View { @State private var log = "Tap a button. Watch this log and whether Safari actually appears.\n" var body: some View { VStack(alignment: .leading, spacing: 16) { Button("Open relative URL") { openTarget(.relative) } .buttonStyle(.borderedProminent) Button("Open absoluteURL") { openTarget(.absolute) } .buttonStyle(.bordered) Button("Clear log") { log = "" } ScrollView { Text(log) .font(.system(.footnote, design: .monospaced)) .textSelection(.enabled) .frame(maxWidth: .infinity, alignment: .leading) } } .padding() } private enum ReproTarget { case relative case absolute } private func append(_ line: String) { log.append(line + "\n") print(line) } private func openTarget(_ target: ReproTarget) { log = "" let base = URL(string: "https://www.example.com")! let relative = URL(string: "about/help", relativeTo: base)! let url = (target == .relative) ? relative : relative.absoluteURL append("target: \(target == .relative ? "relative" : "absoluteURL")") append("url: \(url)") append("absoluteString: \(url.absoluteString)") append("scheme: \(url.scheme ?? "nil")") append("baseURL: \(url.baseURL?.absoluteString ?? "nil")") append("relativeString: \(url.relativeString)") append("canOpenURL: \(UIApplication.shared.canOpenURL(url))") append("Calling UIApplication.shared.open…") append("Did Safari actually appear? Check by eye.") UIApplication.shared.open(url, options: [:]) { success in Task { @MainActor in append("open completion: \(success)") } } } } #Preview { RelativeURLReproView() }
4
0
61
1d
viewDidDisappear is not called on a popped view controller when switching tabs during UITabBarController's reselect pop-to-root on iOS 27
Issue Description Hi, I would like to share an issue with UIViewController's appearance callbacks inside UITabBarController + UINavigationController on iOS 27. When a tab containing a UINavigationController with two view controllers is re-tapped, UIKit starts its built-in animated pop-to-root. On iOS 27, if the user switches to another tab while that pop animation is still in flight, the popped view controller receives viewWillDisappear: (with isMovingFromParent == true), but viewDidDisappear: is never called on it. The appearance callbacks stay unbalanced. This breaks code that relies on viewDidDisappear: + isMovingFromParent to detect that a view controller was popped. Steps to Reproduce Create a UITabBarController with two tabs. The first tab is a UINavigationController. In the first tab, push a second view controller ("Nested"). Tap the first tab item again. UIKit starts the animated pop-to-root. Immediately (while the pop animation is still running), tap the second tab item. Expected vs. Actual Behavior Expected: On iOS 26, "Nested" receives viewWillDisappear: and then viewDidDisappear:, both with isMovingFromParent == true. Actual: On iOS 27, "Nested" receives only viewWillDisappear:. viewDidDisappear: is NOT called, even though "Nested" is no longer in navigationController.viewControllers. Note: On iOS 27, if the second tab is tapped after the pop animation has finished, viewDidDisappear: is delivered correctly. The issue only occurs when the tab switch happens during the pop transition. Environment Xcode Version 27.0 iOS 27.0 iPhone 18 Pro simulator: reproduces iOS 26.0 iPhone 17 Pro simulator: does not reproduce Feedback Assistant Report ID: FB24934469 Minimal Reproduction Example // SceneDelegate.swift import UIKit class SceneDelegate: UIResponder, UIWindowSceneDelegate { var window: UIWindow? func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) { guard let windowScene = scene as? UIWindowScene else { return } let window = UIWindow(windowScene: windowScene) window.rootViewController = TabBarController() window.makeKeyAndVisible() self.window = window } } // TabBarController.swift import UIKit final class TabBarController: UITabBarController { override func viewDidLoad() { super.viewDidLoad() let firstNav = UINavigationController(rootViewController: HomeViewController()) firstNav.tabBarItem = UITabBarItem(title: "First", image: UIImage(systemName: "house"), tag: 0) let second = LoggingViewController(name: "Second") second.tabBarItem = UITabBarItem(title: "Second", image: UIImage(systemName: "star"), tag: 1) viewControllers = [firstNav, second] } } class LoggingViewController: UIViewController { let name: String init(name: String) { self.name = name super.init(nibName: nil, bundle: nil) title = name } required init?(coder: NSCoder) { fatalError() } override func viewDidLoad() { super.viewDidLoad() view.backgroundColor = .systemBackground } override func viewWillDisappear(_ animated: Bool) { super.viewWillDisappear(animated) print("[\(name)] viewWillDisappear isMovingFromParent=\(isMovingFromParent)") } override func viewDidDisappear(_ animated: Bool) { super.viewDidDisappear(animated) print("[\(name)] viewDidDisappear isMovingFromParent=\(isMovingFromParent)") } } final class HomeViewController: LoggingViewController { init() { super.init(name: "Home") } required init?(coder: NSCoder) { fatalError() } override func viewDidLoad() { super.viewDidLoad() navigationItem.rightBarButtonItem = UIBarButtonItem( title: "Push", primaryAction: UIAction { [weak self] _ in self?.navigationController?.pushViewController(LoggingViewController(name: "Nested"), animated: true) } ) } }
Topic: UI Frameworks SubTopic: UIKit
0
0
36
1d
Repeated Swift error breakpoint stops in system frameworks during AppKit startup and window creation
I debug an Objective-C++ AppKit application in CLion. The application runs normally, but a “When any is thrown” breakpoint stops repeatedly during startup and window creation, making it difficult to debug. One stop occurs before any window is created: [NSApplication run] → finishLaunching → _customizeMainMenu → [NSTextView _supportsWritingTools] → GenerativeModels → JSONDecoder → swift_willThrow. LLDB identifies a decoding frame as GenerativeModels.AvailabilityStore.ReadinessEntry.Criteria.init(from:). Other stops occur while NSDocumentController attempts to reopen documents, and while AppKit resets gesture recognizers during NSWindow creation. All the supplied stops reach swift_willThrow; the app continues after resuming. Are these expected handled errors? Is there a supported way to prevent the startup Writing Tools check from throwing? I can provide the complete stacks and a minimal reproduction if helpful. I'm on MacOS Tahoe 26.6.2 (25G83) Xcode 26.4.1 - Build version 17E202 Apple clang version 21.0.0 (clang-2100.0.123.102) I'm building from within CLion 2026.2.3 and using the bundled LLDB (21.1.7), but the problem also occurs when using the one from XCode (21.0) Disabling Apple Intelligence in the OS settings does not help.
Topic: UI Frameworks SubTopic: AppKit
0
0
27
1d
CALayer with valid contents and correct configuration is excluded from window compositing on Apple Silicon (works fine on Intel)
macOS/Hardware details: macOS version: 27.0 (build 26A428) Hardware: Apple Silicon Mac (arm64) App architecture: Native arm64 Xcode/SDK: Built against MacOSX27.0 SDK Deployment target: MACOSX_DEPLOYMENT_TARGET = 26.0 Regression history: Same app/codebase previously built and ran correctly on macOS 13 (Ventura), Intel — issue only appears after migrating the build to Apple Silicon; no changes were made to the affected view's drawing or layer-configuration code between the two builds We have a custom, layer-backed NSView (part of a hand-rolled tree/list control that draws its own content via Core Graphics into the layer's contents) that renders completely blank on screen on Apple Silicon Macs, while an adjacent sibling view using the identical view class, drawing code, and layer configuration renders correctly. Using lldb and Xcode's View Debugger against the live process, we've confirmed: The layer's actual backing content is correct: capturing it directly via -renderInContext: produces the expected fully-drawn image (text and icons all present). Every inspectable property of the broken view/layer (hidden, alphaValue, opaque, wantsLayer, isFlipped/isGeometryFlipped, zPosition, masksToBounds, contentsScale, mask, transform, backgroundColor, contents, sublayers, superlayer) is identical to the working sibling view — no configuration difference exists anywhere. The layer's superlayer link is intact and points to the correct parent, ruling out a detached/orphaned layer. Standard remediation attempts — setNeedsDisplay:, displayIfNeeded, toggling wantsLayer, detaching/reattaching the view from its superview, changing zPosition — all have zero effect. Most notably, directly setting layer.backgroundColor to an opaque solid color on the live, correctly-connected layer (verified via property readback) produces no visible change on screen at all. Because even an unconditional background color change is not reflected, the layer appears to be excluded from what's actually sent to the window server for compositing, rather than simply failing to draw updated content. Since all inspectable state is correct and identical to a working sibling view, we've been unable to identify any application-level cause. The view remains fully interactive — clicks and hit-testing resolve correctly to the right underlying data — only the visual output is missing. Are there known Apple Silicon-specific changes to CALayer/NSView compositing (window server layer inclusion, contentsScale/backing-store allocation, or layer-backed view promotion) that could cause a fully valid, connected CALayer with correct contents to be silently dropped from the composited frame? Any suggestions for further diagnostic tools (e.g. Quartz Debug, CARenderServer logging, or WindowServer compositing traces) to narrow this down further would help.
Topic: UI Frameworks SubTopic: AppKit
0
0
13
1d
SplitViewController removed the ability to have a side menu on iPhone
Sometime pre-iOS 26 it was possible to use a SplitViewController so that on iPhone you saw the master as a side menu (e.g. hamburger), and the detail full screen. While on iPad you would see the master displayed in a sidebar that could be closed, with the detail fullscreen. This has changed, using a SplitViewController on iPhone now forces you into having 2 fullscreen screens, with a push/pop layout and a back button. In situations where you want the detail screen to open first, this results in users opening the app to find a back button already presented, despite having not navigated anywhere. They must "return" to a screen they never saw. I really despise this layout and find it to be quite a UX issue. But given the new iPhone Duo, using the SplitViewController is now one of the easiest ways to maintain the necessary responsiveness needed, forcing us to accept this behaviour on regular iPhones. Can we PLEASE get the old functionality back, where we can explicitly state on iPhone that the master will always be displayed as a menu?
0
0
56
1d
Charts are broken with Xcode 27, Plotting multiple lines
Hi, Charts—specifically those with multiple lines—are broken in Xcode 27. First, I spotted the bug in my program, and then I checked your example. Your own example Plotting-multiple-lines is not working correctly anymore. It shows 1 line or sometimes no lines at all, depending on the order of the data. It depends on how the data is passed to the chart. If the data is passed as separate series, it works. In Visualizing your app’s data it works, but the data is passed as described before. Don't follow Microslop: have the AI ​​generate the code and then skip the tests. This is a serious bug that requires a lot of work to rearrange the data, just to work around the issue. Christian
0
0
221
1d
App Intents and the Document App Xcode Template
I’m working on an app that deals with a list of text items, so I started with the document app template in Xcode. I have the app basically doing what I want it to do, but I want to be a good ecosystem citizen, so I’d like to conform to app intents. I think that app intents will able to do what I want - accepting text and passing it back out - but I can’t figure out how to access the document outside of my content view and associated subviews. Any guidance would be appreciated. Thank you, Don Carlile
1
0
404
2d
macOS 26.7: a side Dock prevents quarter tiling at the adjacent upper corner
I found that the failing corner in native macOS window tiling changes with the Dock position. With the Dock on the right, the upper-right corner produces the right half instead of a quarter. With the Dock on the left, the upper-left corner produces the left half instead of a quarter. With the Dock at the bottom, all four corners produce quarters. Apple's macOS Tahoe guide describes dragging to any corner as a way to tile a window there. Configuration Mac mini Mac14,12, Apple M2 Pro macOS Tahoe 26.7 (25G229) One external iiyama PL4071UH (ProLite X4071UHSU) display, with a [native panel resolution of 3840 × 2160]; no adjacent display and mirroring off. A 3840 × 2160 mode is available in macOS, but it was not the mode used for these measurements. Active macOS display mode reported by CGDisplayMode and System Information: 3008 × 1692 pixels at 60 Hz; the interface “looks like” 1504 × 846 points (2× backing scale). This is a scaled configuration on the 4K display. NSScreen.frame: 1504 × 846 points. NSScreen.visibleFrame with the Dock on the right: approximately 1456 × 816 points (about 48 points removed at the right for the Dock and 30 at the top for the menu bar). macOS reports Television: Yes for this display and exposes an Underscan control in Displays settings. The slider appeared at the “No” end during inspection; its effect on this tiling behavior has not been tested. Dock position changed between right, left, and bottom for the comparison below Dock auto-hide is currently off (com.apple.dock autohide = 0) Native drag-to-edge tiling and the Option-key tiling accelerator enabled; tiled window margins disabled Upper-right Hot Corner configured without a modifier key during the right-Dock measurement Steps to reproduce Open a blank, resizable TextEdit window and enable native drag-to-edge tiling. Set the Dock position to Right in System Settings → Desktop & Dock. Drag the window by its title bar to each screen corner and release after the tiling preview appears. Set the Dock position to Left and repeat. Set the Dock position to Bottom and repeat. Dock-position comparison Dock position Upper-left corner Upper-right corner Lower corners Right quarter right half quarters Left left half quarter quarters Bottom quarter quarter quarters The left- and bottom-Dock comparisons are direct user observations. The right-Dock case was also measured programmatically as described below. This pattern points to a side-Dock interaction with detection of the adjacent upper corner; the internal cause is not yet established. The display's scaled mode and its classification as a television are additional variables worth recording. Neither has been isolated as a cause: the controlled change so far is the Dock position. A useful follow-up would be to repeat the same corner tests at another display mode, including 3840 × 2160, with the Dock kept on the same side, and to record the Underscan setting. Instrumented result with Dock on the right I sampled NSEvent.mouseLocation every 20 ms, used CGEventSource.buttonState to identify the release, and read the window bounds using CGWindowListCopyWindowInfo about 0.6 seconds later. The same TextEdit window ID was observed for all four corner tests. Pointer and window coordinates below use the top-left of the display as (0, 0); dimensions are in macOS points. Release corner Pointer (x, y) Window (x, y, width, height) Result Top left (0, 0) (-1, 30, 727, 409) quarter Top right (1503.98, 0) (727, 30, 728, 816) RIGHT HALF Bottom left (0, 845.98) (-1, 438, 727, 409) quarter Bottom right (1503.98, 845.98) (727, 438, 728, 409) quarter At the upper-right release, the pointer is effectively at the screen's rightmost x coordinate and at y = 0. The resulting window is 816 points high, compared with 409 points for each quarter tile. The Hot Corner did not prevent the pointer from reaching that coordinate. Expected result Dragging to any of the four corners should produce the corresponding quarter regardless of whether the Dock is on the right, left, or bottom.
Topic: UI Frameworks SubTopic: General Tags:
0
0
57
2d
How to implement correct horizontal padding for iPhone Duo
The iPhone Duo outer screen displays a vertical bar on the right edge with view contents inset. A SwiftUI Form displays an appropriate amount of leading padding but 0 padding on the trailing edge, since the vertical bar provides some visual margins already that looks nice. I have a view that looks kind of like a form, multiple stacked text fields, that should align the same way. I used scenePadding to achieve which looks correct on iPhone 18 Pro perfectly aligned with Form, but on iPhone Duo there is extra trailing padding. It doesn't align with my Edit button that remains in the horizontal axis navigation bar (and it is not inset enough on the leading edge, off by a few pixels, interestingly). Note when you unfold it and add the app on the left side in Split View, the vertical bar is on the leading edge, in which case there's too much padding on the leading edge. How can I achieve the correct layout padding/margins? iPhone 18 Pro vs iPhone Duo: My actual app: struct ContentView: View { var body: some View { TabView { NavigationStack { SystemFormView() .navigationTitle("System Form") } .tabItem { Label("System Form", systemImage: "list.bullet.rectangle") } NavigationStack { CustomFormView() .navigationTitle("Custom Form") } .tabItem { Label("Custom Form", systemImage: "rectangle.3.group") } } } } private struct SystemFormView: View { var body: some View { Form { Text("Row 1") Text("Row 2") Text("Row 3") } } } private struct CustomFormView: View { var body: some View { ScrollView { VStack(spacing: 0) { customRow("Row 1") Divider() .padding(.leading) customRow("Row 2") Divider() .padding(.leading) customRow("Row 3") } .background(.background) .scenePadding(.horizontal) } .background(Color(uiColor: .systemGroupedBackground)) } private func customRow(_ title: LocalizedStringKey) -> some View { Text(title) .frame(maxWidth: .infinity, minHeight: 44, alignment: .leading) .padding(.horizontal) } } Note in UIKit, UITableViewController with the inset grouped style has the same layout as Form. A custom view hierarchy can achieve the exact same placement/padding/margins by following these steps: create a scroll view and a content view, set preservesSuperviewLayoutMargins = true on both views, constrain the scroll view to the root view on all edges, constrain the content view to the scrollView.contentLayoutGuide on all edges, constrain the content view width anchor to the scrollView.frameLayoutGuide.widthAnchor, then constrain subviews of the content view to the contentView.layoutMarginsGuide. So I know how to do it in UIKit, how do we in SwiftUI? Thanks!
Topic: UI Frameworks SubTopic: SwiftUI
3
1
169
2d
Bar layout guides are offset by the vertical-bar inset for views inside a UINavigationController when verticalBarEdge is leading
Configuration: Xcode 27.1 (27A9269) iOS 27.1 Simulator (24A94401), iPhone Duo macOS 27.2 (26B5086k) On iOS 27.1, when the vertical bar is on the leading edge, UINavigationController adds a leading safe area inset for the vertical bar (84 pt on iPhone Duo outer display) that the window itself does not have. Bar layout guides (UIView.layoutGuide(for: .bar(onEdge:extent:))) requested from any view inside the navigation controller are then resolved against that inset instead of the actual bar strip: Left-edge bar guides are pinned to x = 84 (the inner edge of the inset) instead of being centered in the vertical bar strip. Top/bottom bar guides start at x = 84. This part matches the mirrored trailing-edge behavior. The same guides requested from a view outside the navigation controller (the window's root view) put the left-edge guides correctly inside the strip, centered at x = 48. They are exact mirrors of the trailing-edge results. With the vertical bar on the trailing edge, everything is consistent: the window itself carries the 84 pt trailing inset and an active occlusion reserved region for the vertical status bar, and guides are identical whether requested from inside or outside the navigation controller. So the leading and trailing configurations are asymmetric. With a trailing bar, the vertical-bar inset lives on the window. With a leading bar, it exists only on UINavigationController's content, and the bar layout region math appears to treat it as an ordinary safe-area inset to avoid rather than as the bar strip. This happens with the navigation bar hidden via setNavigationBarHidden(true, animated: false). (Hiding it by setting navigationBar.isHidden = true additionally shifts the top guides down, which we assume is expected since the controller still considers the bar visible.) Steps to reproduce: Build and run the attached sample on the iPhone Duo simulator (iOS 27.1), outer display, portrait. Put the app in the configuration where traitCollection.verticalBarEdge == .leading. With "Plain root" selected, note the yellow (left-edge) bar guides: 22/44/88 pt bands share one center line inside the leading strip. Tap the center button and select "UINavigationController" (the navigation bar is hidden with setNavigationBarHidden(true, animated: false)). Observe the yellow bands and check the console output (lines prefixed with [BarLayoutGuidePlayground]). Repeat steps 3–5 with verticalBarEdge == .trailing and compare the green (right-edge) bands. Expected results: Bar layout guides resolve the same way for leading and trailing vertical bars, and the same way whether the requesting view is the window root or a child of UINavigationController. With a leading bar, the left-edge guides should be centered in the vertical bar strip (x = 37 / 26 / 4 for extents 22 / 44 / 88 in a 469 pt wide window), mirroring the trailing results (x = 410 / 399 / 377). Actual results: With a leading bar, inside UINavigationController: view.safeAreaInsets = (top: 0, left: 84, bottom: 34, right: 0) window.safeAreaInsets = (top: 0, left: 0, bottom: 34, right: 0) left 22: (84, 16, 22, 619) left 44: (84, 16, 44, 619) left 88: (84, 16, 88, 619) top 22: (84, 37, 376.33, 22) Same guides requested from the window's root view: left 22: (37, 16, 22, 619) left 44: (26, 16, 44, 619) left 88: (4, 16, 88, 619) top 22: (16, 37, 444.33, 22) With a trailing bar (identical from both views): view.safeAreaInsets = (top: 0, left: 0, bottom: 34, right: 84) window.safeAreaInsets = (top: 0, left: 0, bottom: 34, right: 84) occlusion reserved region (active): (385, 0, 84, 120) right 22: (410, 120, 22, 515) right 44: (399, 120, 44, 515) right 88: (377, 120, 88, 515) top 22: (8.67, 37, 376.33, 22) With a leading bar there is no active occlusion region for the status bar, and the window has no leading inset, yet UINavigationController adds one. Sample project
Topic: UI Frameworks SubTopic: UIKit
3
2
155
2d
How to separate/add space between Liquid Glass toolbar items when using ToolbarOverflowMenu
When optimizing for iPhone Duo (and in general) I understand the recommendation is to replace custom More (...) menus with the system overflow menu, otherwise it's possible you can see two (...) buttons or get the custom menu nested inside the system overflow menu. Eek. With the following code, both (+) and (...) are unexpectedly inside one shared Liquid Glass background. How do you separate / add space between them or is this a bug, if so is there a workaround? struct ContentView: View { var body: some View { NavigationStack { Text("Hello, World") .toolbar { ToolbarItem { Button("Add", systemImage: "plus") { } } ToolbarSpacer(.fixed) ToolbarOverflowMenu { Button("Settings", systemImage: "gearshape") { } } } } } } Here's my original code that display two separate buttons as expected: struct ContentView: View { var body: some View { NavigationStack { Text("Hello, World") .toolbar { ToolbarItem { Button("Add", systemImage: "plus") { } } ToolbarSpacer(.fixed) ToolbarItem { Menu { Button("Settings", systemImage: "gearshape") { } } label: { Label("More", systemImage: "ellipsis") } } } } } } Why do I care you might ask? When the user turns on filters in my app, a filter toolbar item is shown, and I want the (+) to remain separate from the grouped filter and more buttons. (+) is like the primary action that should stand alone, like it does in the Wallet app.
Topic: UI Frameworks SubTopic: SwiftUI
3
1
98
2d
A Summary of the iPhone Duo Group Lab
Group Labs are a unique opportunity for the community to submit questions directly to a panel of Apple engineers and designers. Here are the highlights from the iPhone Duo Group Labs: How should apps preserve navigation and UI state when switching between the inner and outer displays? Treat display transitions as size-class and trait changes, not a scene disconnect or app termination; your process stays alive. For more information, see Prepare your app for iPhone Duo. For state that must survive a scene disconnect/reconnect, implement stateRestorationActivity(for:) to save an NSUserActivity Restoring your app's state. Do multiple instances of the same app on iPhone Duo share UserDefaults/@AppStorage state? Multiple instances of your app's UI on iPhone Duo behave similarly to multi-window support on iPadOS. To learn more, see Leverage multiple displays and scenes on iPhone Duo. Both UserDefaults and AppStorage are app-wide, not per-window, stores. If a full-screen app on the inner display is closed, does it move to the outer display or get backgrounded? iPhone Duo honors UIRequiresFullScreen and apps adapt in place as the device opens and closes rather than backgrounding. To learn more, watch Prepare your app for iPhone Duo. How should apps preserve state — text input, scroll position, video playback, camera sessions — during hinge angle transitions? For example, when a LazyVGrid's column count changes because the device folds, does SwiftUI preserve scroll position automatically, or should you use scrollPosition(id:)? The system generally preserves text input and scroll position automatically since hinge angle changes are represented as size-class and trait updates, not a scene disconnect or app termination. This applies even to cases like a LazyVGrid column-count change triggered by opening or closing the device — apps typically don't need to manually manage scroll position with scrollPosition(id:anchor:) for this transition. For more info, see Prepare your app for iPhone Duo. How can apps preserve what someone is doing when switching displays or folding/unfolding? Treat this as a resize/trait-change event, not app teardown — your process keeps running as size classes change. See Prepare your app for iPhone Duo to learn more. For scenes that actually disconnect and reconnect, implement stateRestorationActivity(for:) to save an NSUserActivity Restoring your app's state. How does actively playing video behave through the hinge angle animation? The system generally preserves video playback and player position automatically since hinge angle changes are represented as size-class and trait updates, not a scene disconnect or app termination. AVKit will scale and resize the video automatically. If a user folds or unfolds the device mid-checkout, what does the system preserve automatically, and what should the app manage itself to avoid lost input or duplicate requests? When someone opens or closes an iPhone Duo, the system represents this as a size-class and trait collection change, not a scene disconnect or app teardown, so in-memory state like input fields typically persists automatically since the app’s process keeps running. For more info, see Prepare your app for iPhone Duo. How should apps handle the keyboard and text input when the device folds or unfolds while typing? As iPhone Duo folds or unfolds, the available screen geometry and framing change. Ensure your app adopts standard layout controls, containers, and size classes to handle resizability gracefully across all poses. When a text field becomes first responder, the system automatically shows the keyboard and binds its input to the text field. Because the appearance of the keyboard has the potential to obscure portions of your user interface, you should update your interface as needed to ensure that the text field being edited remains visible. Use keyboard notifications such as keyboardWillShowNotification, keyboardWillHideNotification, and keyboardWillChangeFrameNotification to detect the appearance and disappearance of the keyboard and to make necessary changes to your interface layout. To learn more, see UITextField. If someone is typing and closes iPhone Duo, does the keyboard/editing session survive the hinge transition, or does it get a new scene? When a user types and closes iPhone Duo, the active editing session and keyboard do not get a completely new scene. Instead, the app undergoes a dynamic resizing and transitions from the inner display to the compact outer display, maintaining the existing scene and application state. For more info, watch Prepare your app for iPhone Duo.
Replies
16
Boosts
0
Views
933
Activity
3d
Content Not using Available Space In UICollectionViewListCell in iPhone Duo
Instead of centering the content within the available cell space, the content is to the left of center in an iPhone Duo simulation. The content is fine in an iPhone Pro simulation.
Replies
1
Boosts
0
Views
72
Activity
4h
How to Keep Out a Tinted navigationbar from the Combined Status Bar Region in iPhone Duo using Swiftui
I think the title says it all.
Replies
1
Boosts
0
Views
58
Activity
4h
Can a Notes note be dragged into another app on iPhone Duo?
I’m adding drag-and-drop support to my app for multitasking on iPhone Duo. My app supports text/note content. Currently, a user can move content from Apple Notes into my app using Share or Copy/Paste. ** Questions** Can a note from the Notes app be dragged directly into another app during multitasking, similar to dragging a photo? If so, what content type does Notes provide through the drag-and-drop session? For example, is the note exposed as plain text (public.plain-text / UTType.plainText), rich text, or another transferable type? My goal is for the user to drag a note from Notes into my app and have it behave essentially like Copy → Paste, without requiring the Share sheet. Thank you.
Replies
0
Boosts
0
Views
31
Activity
6h
SwiftUI Document API Duplicate Function hangs on macOS 27
In a macOS 27 app using DocumentGroup(editor:makeDocument:) with a type conforming to the new Document protocol, choosing File › Duplicate hangs the app permanently (0% CPU, spinning beach ball, must force quit). The main thread is blocked in URLPlatformDocument.read(from:ofType:) waiting on a dispatch semaphore. That synchronous NSDocument read path is reached from NSDocumentController.duplicateDocumentWithContentsOfURL(:copying:displayName:) → makeDocumentForURL(:withContentsOf:ofType:) → NSDocument.init(for:withContentsOf:ofType:). The work the semaphore waits for never runs: the app's makeDocument closure is never called. The SDK declares makeDocument and ReadableDocument.apply(snapshot:previous:) as @MainActor, so blocking the main thread while waiting for them can never complete. This reproduces with Apple's unmodified sample code project "Building a Document-Based App with SwiftUI" (no code or project changes; only a signing team set). Our own app, which uses a custom DocumentReader/DocumentWriter with Source/Destination == URL, hangs with the identical stack. Has anyone found any workaround? Filed Feedback FB24949862
Topic: UI Frameworks SubTopic: SwiftUI
Replies
0
Boosts
0
Views
27
Activity
7h
sidebarAdaptable Design Problem
This is what Apple's Destination Video Sample App looks like on iPhone Duo built with SDK 27.1 beta. Two things: Items that should not appear in the tab bar appear. There is no sidebar for iPhone Duo. So my problem is: is this a bug or a design on purpose? Will sidebarAdaptable gets a sidebar on iPhone Duo? Or at least, how to hide these things that should only appear in the sidebar? The sample app uses .defaultVisibility(, for:) and .hidden() but obviously none of these takes effect.
Topic: UI Frameworks SubTopic: SwiftUI
Replies
1
Boosts
1
Views
170
Activity
7h
How to check for multiple scene support on iPhone Duo?
I have an iOS app that supports multiple scenes on the iPad, and which has an "Open in Another Window" feature which creates a new window scene. I would like to bring this feature to the iPhone Duo. On the iPhone Duo, of course, creating new windows is only supported when the device is open; when it is closed, creating new windows does not work. (If you try, an error is thrown.) Until now, the way I have checked whether my "Open in Another Window" feature should be available is to check to see if UIApplication.shared.supportsMultipleScenes is true. This has always returned false for previous iPhones and true for iPads. Unfortunately, however, this does not work as expected on the iPhone Duo. On the Duo, I would expect supportsMultipleScenes to return true when the device is open, but false when it is closed. This is not the case: it returns true for all poses. (Filed as #FB24948411 as this doesn't seem right to me.) So it does not help me decide whether the feature should be available. UIWindowScene.ActivationAction does work as expected when used in a menu, with the action auto-hiding when the Duo is in the closed pose. In my app, though, I need more than just an auto-hiding menu item; I need to check whether creating a new window is currently possible for certain UI availability decisions. What, then, is the correct way of checking this, if it's not with supportsMultipleScenes? Given that UIWindowScene.ActivationAction is able to hide itself, I assume there is some better way of checking that I have missed.
Topic: UI Frameworks SubTopic: UIKit Tags:
Replies
0
Boosts
0
Views
36
Activity
9h
Supported way to put an iPhone Duo simulator into the unfolded state programmatically
The Duo simulator boots showing only the outer display: the window is fixed at 382×644 pt and our layout classifier always reports the compact stack mode. We measured this on two separate clean boots (shutdown, erase, boot). xcrun simctl help lists no subcommand for folding, posture, or selecting the inner display — we read the full list. xcrun simctl io screenshot does reveal a second display (LCD-1, 2007×2853 px, aspect 0.70, close to the 669×951 inner portrait size). Unfolding manually in the Simulator UI works and the app then renders the two-column layout correctly, but we could not find a programmatic equivalent. Is there a supported way to unfold a Duo simulator from the command line or from XCTest?
Topic: UI Frameworks SubTopic: SwiftUI
Replies
3
Boosts
3
Views
702
Activity
1d
Enable iPhone Duo Upside Down Orientation
Ever since the iPhone X, upside-down orientation on the iPhone has been disabled by design. I haven't found any official documentation explaining why, but my guess is it has to do with Face ID and the top notch. However, now that the iPhone Duo has no Face ID or notch—and includes reserved occlusion regions—why not enable upside-down rotation? As of iOS 27.1, it remains disabled. Leaving it turned off only confuses users, making them think their favorite apps are frozen when they won't rotate.
Topic: UI Frameworks SubTopic: SwiftUI
Replies
1
Boosts
1
Views
308
Activity
1d
iPhone Duo and the Safe-Area
I took a screenshot of the Safety Area's and Occlusions on the iPhone Duo outer display. The article Designing for iPhone Duo tells us to... Consider using the full display width for interfaces where bars aren’t necessary. Some layouts can span the full display, which works well for visual, immersive interfaces that don’t scroll, as long as nothing conflicts with the Dynamic Island or the status bar. Calculator, for example, occupies the full width of the display. You can also combine both approaches, letting a background image or header span the full width while scrollable content stays inset. The Graphics Content can easily take up the full space which can be achieved by ignoring the safe area (.ignoresSafeArea()). And knowing the iPhone Duo there is no occlusion so I can also ignore the safe area for the interactable content. However we now are entering an awkward state. Because now I need to make decisions based on a specific device. Knowing the iPhone Duo I can ignore horizontal safe area and expand to full width because there is no occlusions here, but ignoring the safe-area may result in unexpected behavior on other (future) devices which then requires me to use code that specificly targets certain devices. I wished SwiftUI had something that I could safely expand the interactable content the full width.
Topic: UI Frameworks SubTopic: SwiftUI
Replies
2
Boosts
0
Views
105
Activity
1d
iOS 27: UIApplication.shared.open fail for relative URL values that resolve to valid https URLs
A URL created with URL(string:relativeTo:) that used to work in iOS26 and below with UIApplication.shared.open stopped working in iOS27, the app has not been built yet with iOS27 SDK. Have anyone seen this issue, all the links work perfectly in iOS26 and below. We found a solution to use .absoluteURL but still want to check with the community, I havent seen any mention of this this that it will break try the below sample code import UIKit struct RelativeURLReproView: View { @State private var log = "Tap a button. Watch this log and whether Safari actually appears.\n" var body: some View { VStack(alignment: .leading, spacing: 16) { Button("Open relative URL") { openTarget(.relative) } .buttonStyle(.borderedProminent) Button("Open absoluteURL") { openTarget(.absolute) } .buttonStyle(.bordered) Button("Clear log") { log = "" } ScrollView { Text(log) .font(.system(.footnote, design: .monospaced)) .textSelection(.enabled) .frame(maxWidth: .infinity, alignment: .leading) } } .padding() } private enum ReproTarget { case relative case absolute } private func append(_ line: String) { log.append(line + "\n") print(line) } private func openTarget(_ target: ReproTarget) { log = "" let base = URL(string: "https://www.example.com")! let relative = URL(string: "about/help", relativeTo: base)! let url = (target == .relative) ? relative : relative.absoluteURL append("target: \(target == .relative ? "relative" : "absoluteURL")") append("url: \(url)") append("absoluteString: \(url.absoluteString)") append("scheme: \(url.scheme ?? "nil")") append("baseURL: \(url.baseURL?.absoluteString ?? "nil")") append("relativeString: \(url.relativeString)") append("canOpenURL: \(UIApplication.shared.canOpenURL(url))") append("Calling UIApplication.shared.open…") append("Did Safari actually appear? Check by eye.") UIApplication.shared.open(url, options: [:]) { success in Task { @MainActor in append("open completion: \(success)") } } } } #Preview { RelativeURLReproView() }
Replies
4
Boosts
0
Views
61
Activity
1d
viewDidDisappear is not called on a popped view controller when switching tabs during UITabBarController's reselect pop-to-root on iOS 27
Issue Description Hi, I would like to share an issue with UIViewController's appearance callbacks inside UITabBarController + UINavigationController on iOS 27. When a tab containing a UINavigationController with two view controllers is re-tapped, UIKit starts its built-in animated pop-to-root. On iOS 27, if the user switches to another tab while that pop animation is still in flight, the popped view controller receives viewWillDisappear: (with isMovingFromParent == true), but viewDidDisappear: is never called on it. The appearance callbacks stay unbalanced. This breaks code that relies on viewDidDisappear: + isMovingFromParent to detect that a view controller was popped. Steps to Reproduce Create a UITabBarController with two tabs. The first tab is a UINavigationController. In the first tab, push a second view controller ("Nested"). Tap the first tab item again. UIKit starts the animated pop-to-root. Immediately (while the pop animation is still running), tap the second tab item. Expected vs. Actual Behavior Expected: On iOS 26, "Nested" receives viewWillDisappear: and then viewDidDisappear:, both with isMovingFromParent == true. Actual: On iOS 27, "Nested" receives only viewWillDisappear:. viewDidDisappear: is NOT called, even though "Nested" is no longer in navigationController.viewControllers. Note: On iOS 27, if the second tab is tapped after the pop animation has finished, viewDidDisappear: is delivered correctly. The issue only occurs when the tab switch happens during the pop transition. Environment Xcode Version 27.0 iOS 27.0 iPhone 18 Pro simulator: reproduces iOS 26.0 iPhone 17 Pro simulator: does not reproduce Feedback Assistant Report ID: FB24934469 Minimal Reproduction Example // SceneDelegate.swift import UIKit class SceneDelegate: UIResponder, UIWindowSceneDelegate { var window: UIWindow? func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) { guard let windowScene = scene as? UIWindowScene else { return } let window = UIWindow(windowScene: windowScene) window.rootViewController = TabBarController() window.makeKeyAndVisible() self.window = window } } // TabBarController.swift import UIKit final class TabBarController: UITabBarController { override func viewDidLoad() { super.viewDidLoad() let firstNav = UINavigationController(rootViewController: HomeViewController()) firstNav.tabBarItem = UITabBarItem(title: "First", image: UIImage(systemName: "house"), tag: 0) let second = LoggingViewController(name: "Second") second.tabBarItem = UITabBarItem(title: "Second", image: UIImage(systemName: "star"), tag: 1) viewControllers = [firstNav, second] } } class LoggingViewController: UIViewController { let name: String init(name: String) { self.name = name super.init(nibName: nil, bundle: nil) title = name } required init?(coder: NSCoder) { fatalError() } override func viewDidLoad() { super.viewDidLoad() view.backgroundColor = .systemBackground } override func viewWillDisappear(_ animated: Bool) { super.viewWillDisappear(animated) print("[\(name)] viewWillDisappear isMovingFromParent=\(isMovingFromParent)") } override func viewDidDisappear(_ animated: Bool) { super.viewDidDisappear(animated) print("[\(name)] viewDidDisappear isMovingFromParent=\(isMovingFromParent)") } } final class HomeViewController: LoggingViewController { init() { super.init(name: "Home") } required init?(coder: NSCoder) { fatalError() } override func viewDidLoad() { super.viewDidLoad() navigationItem.rightBarButtonItem = UIBarButtonItem( title: "Push", primaryAction: UIAction { [weak self] _ in self?.navigationController?.pushViewController(LoggingViewController(name: "Nested"), animated: true) } ) } }
Topic: UI Frameworks SubTopic: UIKit
Replies
0
Boosts
0
Views
36
Activity
1d
Repeated Swift error breakpoint stops in system frameworks during AppKit startup and window creation
I debug an Objective-C++ AppKit application in CLion. The application runs normally, but a “When any is thrown” breakpoint stops repeatedly during startup and window creation, making it difficult to debug. One stop occurs before any window is created: [NSApplication run] → finishLaunching → _customizeMainMenu → [NSTextView _supportsWritingTools] → GenerativeModels → JSONDecoder → swift_willThrow. LLDB identifies a decoding frame as GenerativeModels.AvailabilityStore.ReadinessEntry.Criteria.init(from:). Other stops occur while NSDocumentController attempts to reopen documents, and while AppKit resets gesture recognizers during NSWindow creation. All the supplied stops reach swift_willThrow; the app continues after resuming. Are these expected handled errors? Is there a supported way to prevent the startup Writing Tools check from throwing? I can provide the complete stacks and a minimal reproduction if helpful. I'm on MacOS Tahoe 26.6.2 (25G83) Xcode 26.4.1 - Build version 17E202 Apple clang version 21.0.0 (clang-2100.0.123.102) I'm building from within CLion 2026.2.3 and using the bundled LLDB (21.1.7), but the problem also occurs when using the one from XCode (21.0) Disabling Apple Intelligence in the OS settings does not help.
Topic: UI Frameworks SubTopic: AppKit
Replies
0
Boosts
0
Views
27
Activity
1d
CALayer with valid contents and correct configuration is excluded from window compositing on Apple Silicon (works fine on Intel)
macOS/Hardware details: macOS version: 27.0 (build 26A428) Hardware: Apple Silicon Mac (arm64) App architecture: Native arm64 Xcode/SDK: Built against MacOSX27.0 SDK Deployment target: MACOSX_DEPLOYMENT_TARGET = 26.0 Regression history: Same app/codebase previously built and ran correctly on macOS 13 (Ventura), Intel — issue only appears after migrating the build to Apple Silicon; no changes were made to the affected view's drawing or layer-configuration code between the two builds We have a custom, layer-backed NSView (part of a hand-rolled tree/list control that draws its own content via Core Graphics into the layer's contents) that renders completely blank on screen on Apple Silicon Macs, while an adjacent sibling view using the identical view class, drawing code, and layer configuration renders correctly. Using lldb and Xcode's View Debugger against the live process, we've confirmed: The layer's actual backing content is correct: capturing it directly via -renderInContext: produces the expected fully-drawn image (text and icons all present). Every inspectable property of the broken view/layer (hidden, alphaValue, opaque, wantsLayer, isFlipped/isGeometryFlipped, zPosition, masksToBounds, contentsScale, mask, transform, backgroundColor, contents, sublayers, superlayer) is identical to the working sibling view — no configuration difference exists anywhere. The layer's superlayer link is intact and points to the correct parent, ruling out a detached/orphaned layer. Standard remediation attempts — setNeedsDisplay:, displayIfNeeded, toggling wantsLayer, detaching/reattaching the view from its superview, changing zPosition — all have zero effect. Most notably, directly setting layer.backgroundColor to an opaque solid color on the live, correctly-connected layer (verified via property readback) produces no visible change on screen at all. Because even an unconditional background color change is not reflected, the layer appears to be excluded from what's actually sent to the window server for compositing, rather than simply failing to draw updated content. Since all inspectable state is correct and identical to a working sibling view, we've been unable to identify any application-level cause. The view remains fully interactive — clicks and hit-testing resolve correctly to the right underlying data — only the visual output is missing. Are there known Apple Silicon-specific changes to CALayer/NSView compositing (window server layer inclusion, contentsScale/backing-store allocation, or layer-backed view promotion) that could cause a fully valid, connected CALayer with correct contents to be silently dropped from the composited frame? Any suggestions for further diagnostic tools (e.g. Quartz Debug, CARenderServer logging, or WindowServer compositing traces) to narrow this down further would help.
Topic: UI Frameworks SubTopic: AppKit
Replies
0
Boosts
0
Views
13
Activity
1d
SplitViewController removed the ability to have a side menu on iPhone
Sometime pre-iOS 26 it was possible to use a SplitViewController so that on iPhone you saw the master as a side menu (e.g. hamburger), and the detail full screen. While on iPad you would see the master displayed in a sidebar that could be closed, with the detail fullscreen. This has changed, using a SplitViewController on iPhone now forces you into having 2 fullscreen screens, with a push/pop layout and a back button. In situations where you want the detail screen to open first, this results in users opening the app to find a back button already presented, despite having not navigated anywhere. They must "return" to a screen they never saw. I really despise this layout and find it to be quite a UX issue. But given the new iPhone Duo, using the SplitViewController is now one of the easiest ways to maintain the necessary responsiveness needed, forcing us to accept this behaviour on regular iPhones. Can we PLEASE get the old functionality back, where we can explicitly state on iPhone that the master will always be displayed as a menu?
Replies
0
Boosts
0
Views
56
Activity
1d
Charts are broken with Xcode 27, Plotting multiple lines
Hi, Charts—specifically those with multiple lines—are broken in Xcode 27. First, I spotted the bug in my program, and then I checked your example. Your own example Plotting-multiple-lines is not working correctly anymore. It shows 1 line or sometimes no lines at all, depending on the order of the data. It depends on how the data is passed to the chart. If the data is passed as separate series, it works. In Visualizing your app’s data it works, but the data is passed as described before. Don't follow Microslop: have the AI ​​generate the code and then skip the tests. This is a serious bug that requires a lot of work to rearrange the data, just to work around the issue. Christian
Replies
0
Boosts
0
Views
221
Activity
1d
App Intents and the Document App Xcode Template
I’m working on an app that deals with a list of text items, so I started with the document app template in Xcode. I have the app basically doing what I want it to do, but I want to be a good ecosystem citizen, so I’d like to conform to app intents. I think that app intents will able to do what I want - accepting text and passing it back out - but I can’t figure out how to access the document outside of my content view and associated subviews. Any guidance would be appreciated. Thank you, Don Carlile
Replies
1
Boosts
0
Views
404
Activity
2d
macOS 26.7: a side Dock prevents quarter tiling at the adjacent upper corner
I found that the failing corner in native macOS window tiling changes with the Dock position. With the Dock on the right, the upper-right corner produces the right half instead of a quarter. With the Dock on the left, the upper-left corner produces the left half instead of a quarter. With the Dock at the bottom, all four corners produce quarters. Apple's macOS Tahoe guide describes dragging to any corner as a way to tile a window there. Configuration Mac mini Mac14,12, Apple M2 Pro macOS Tahoe 26.7 (25G229) One external iiyama PL4071UH (ProLite X4071UHSU) display, with a [native panel resolution of 3840 × 2160]; no adjacent display and mirroring off. A 3840 × 2160 mode is available in macOS, but it was not the mode used for these measurements. Active macOS display mode reported by CGDisplayMode and System Information: 3008 × 1692 pixels at 60 Hz; the interface “looks like” 1504 × 846 points (2× backing scale). This is a scaled configuration on the 4K display. NSScreen.frame: 1504 × 846 points. NSScreen.visibleFrame with the Dock on the right: approximately 1456 × 816 points (about 48 points removed at the right for the Dock and 30 at the top for the menu bar). macOS reports Television: Yes for this display and exposes an Underscan control in Displays settings. The slider appeared at the “No” end during inspection; its effect on this tiling behavior has not been tested. Dock position changed between right, left, and bottom for the comparison below Dock auto-hide is currently off (com.apple.dock autohide = 0) Native drag-to-edge tiling and the Option-key tiling accelerator enabled; tiled window margins disabled Upper-right Hot Corner configured without a modifier key during the right-Dock measurement Steps to reproduce Open a blank, resizable TextEdit window and enable native drag-to-edge tiling. Set the Dock position to Right in System Settings → Desktop & Dock. Drag the window by its title bar to each screen corner and release after the tiling preview appears. Set the Dock position to Left and repeat. Set the Dock position to Bottom and repeat. Dock-position comparison Dock position Upper-left corner Upper-right corner Lower corners Right quarter right half quarters Left left half quarter quarters Bottom quarter quarter quarters The left- and bottom-Dock comparisons are direct user observations. The right-Dock case was also measured programmatically as described below. This pattern points to a side-Dock interaction with detection of the adjacent upper corner; the internal cause is not yet established. The display's scaled mode and its classification as a television are additional variables worth recording. Neither has been isolated as a cause: the controlled change so far is the Dock position. A useful follow-up would be to repeat the same corner tests at another display mode, including 3840 × 2160, with the Dock kept on the same side, and to record the Underscan setting. Instrumented result with Dock on the right I sampled NSEvent.mouseLocation every 20 ms, used CGEventSource.buttonState to identify the release, and read the window bounds using CGWindowListCopyWindowInfo about 0.6 seconds later. The same TextEdit window ID was observed for all four corner tests. Pointer and window coordinates below use the top-left of the display as (0, 0); dimensions are in macOS points. Release corner Pointer (x, y) Window (x, y, width, height) Result Top left (0, 0) (-1, 30, 727, 409) quarter Top right (1503.98, 0) (727, 30, 728, 816) RIGHT HALF Bottom left (0, 845.98) (-1, 438, 727, 409) quarter Bottom right (1503.98, 845.98) (727, 438, 728, 409) quarter At the upper-right release, the pointer is effectively at the screen's rightmost x coordinate and at y = 0. The resulting window is 816 points high, compared with 409 points for each quarter tile. The Hot Corner did not prevent the pointer from reaching that coordinate. Expected result Dragging to any of the four corners should produce the corresponding quarter regardless of whether the Dock is on the right, left, or bottom.
Topic: UI Frameworks SubTopic: General Tags:
Replies
0
Boosts
0
Views
57
Activity
2d
How to implement correct horizontal padding for iPhone Duo
The iPhone Duo outer screen displays a vertical bar on the right edge with view contents inset. A SwiftUI Form displays an appropriate amount of leading padding but 0 padding on the trailing edge, since the vertical bar provides some visual margins already that looks nice. I have a view that looks kind of like a form, multiple stacked text fields, that should align the same way. I used scenePadding to achieve which looks correct on iPhone 18 Pro perfectly aligned with Form, but on iPhone Duo there is extra trailing padding. It doesn't align with my Edit button that remains in the horizontal axis navigation bar (and it is not inset enough on the leading edge, off by a few pixels, interestingly). Note when you unfold it and add the app on the left side in Split View, the vertical bar is on the leading edge, in which case there's too much padding on the leading edge. How can I achieve the correct layout padding/margins? iPhone 18 Pro vs iPhone Duo: My actual app: struct ContentView: View { var body: some View { TabView { NavigationStack { SystemFormView() .navigationTitle("System Form") } .tabItem { Label("System Form", systemImage: "list.bullet.rectangle") } NavigationStack { CustomFormView() .navigationTitle("Custom Form") } .tabItem { Label("Custom Form", systemImage: "rectangle.3.group") } } } } private struct SystemFormView: View { var body: some View { Form { Text("Row 1") Text("Row 2") Text("Row 3") } } } private struct CustomFormView: View { var body: some View { ScrollView { VStack(spacing: 0) { customRow("Row 1") Divider() .padding(.leading) customRow("Row 2") Divider() .padding(.leading) customRow("Row 3") } .background(.background) .scenePadding(.horizontal) } .background(Color(uiColor: .systemGroupedBackground)) } private func customRow(_ title: LocalizedStringKey) -> some View { Text(title) .frame(maxWidth: .infinity, minHeight: 44, alignment: .leading) .padding(.horizontal) } } Note in UIKit, UITableViewController with the inset grouped style has the same layout as Form. A custom view hierarchy can achieve the exact same placement/padding/margins by following these steps: create a scroll view and a content view, set preservesSuperviewLayoutMargins = true on both views, constrain the scroll view to the root view on all edges, constrain the content view to the scrollView.contentLayoutGuide on all edges, constrain the content view width anchor to the scrollView.frameLayoutGuide.widthAnchor, then constrain subviews of the content view to the contentView.layoutMarginsGuide. So I know how to do it in UIKit, how do we in SwiftUI? Thanks!
Topic: UI Frameworks SubTopic: SwiftUI
Replies
3
Boosts
1
Views
169
Activity
2d
Bar layout guides are offset by the vertical-bar inset for views inside a UINavigationController when verticalBarEdge is leading
Configuration: Xcode 27.1 (27A9269) iOS 27.1 Simulator (24A94401), iPhone Duo macOS 27.2 (26B5086k) On iOS 27.1, when the vertical bar is on the leading edge, UINavigationController adds a leading safe area inset for the vertical bar (84 pt on iPhone Duo outer display) that the window itself does not have. Bar layout guides (UIView.layoutGuide(for: .bar(onEdge:extent:))) requested from any view inside the navigation controller are then resolved against that inset instead of the actual bar strip: Left-edge bar guides are pinned to x = 84 (the inner edge of the inset) instead of being centered in the vertical bar strip. Top/bottom bar guides start at x = 84. This part matches the mirrored trailing-edge behavior. The same guides requested from a view outside the navigation controller (the window's root view) put the left-edge guides correctly inside the strip, centered at x = 48. They are exact mirrors of the trailing-edge results. With the vertical bar on the trailing edge, everything is consistent: the window itself carries the 84 pt trailing inset and an active occlusion reserved region for the vertical status bar, and guides are identical whether requested from inside or outside the navigation controller. So the leading and trailing configurations are asymmetric. With a trailing bar, the vertical-bar inset lives on the window. With a leading bar, it exists only on UINavigationController's content, and the bar layout region math appears to treat it as an ordinary safe-area inset to avoid rather than as the bar strip. This happens with the navigation bar hidden via setNavigationBarHidden(true, animated: false). (Hiding it by setting navigationBar.isHidden = true additionally shifts the top guides down, which we assume is expected since the controller still considers the bar visible.) Steps to reproduce: Build and run the attached sample on the iPhone Duo simulator (iOS 27.1), outer display, portrait. Put the app in the configuration where traitCollection.verticalBarEdge == .leading. With "Plain root" selected, note the yellow (left-edge) bar guides: 22/44/88 pt bands share one center line inside the leading strip. Tap the center button and select "UINavigationController" (the navigation bar is hidden with setNavigationBarHidden(true, animated: false)). Observe the yellow bands and check the console output (lines prefixed with [BarLayoutGuidePlayground]). Repeat steps 3–5 with verticalBarEdge == .trailing and compare the green (right-edge) bands. Expected results: Bar layout guides resolve the same way for leading and trailing vertical bars, and the same way whether the requesting view is the window root or a child of UINavigationController. With a leading bar, the left-edge guides should be centered in the vertical bar strip (x = 37 / 26 / 4 for extents 22 / 44 / 88 in a 469 pt wide window), mirroring the trailing results (x = 410 / 399 / 377). Actual results: With a leading bar, inside UINavigationController: view.safeAreaInsets = (top: 0, left: 84, bottom: 34, right: 0) window.safeAreaInsets = (top: 0, left: 0, bottom: 34, right: 0) left 22: (84, 16, 22, 619) left 44: (84, 16, 44, 619) left 88: (84, 16, 88, 619) top 22: (84, 37, 376.33, 22) Same guides requested from the window's root view: left 22: (37, 16, 22, 619) left 44: (26, 16, 44, 619) left 88: (4, 16, 88, 619) top 22: (16, 37, 444.33, 22) With a trailing bar (identical from both views): view.safeAreaInsets = (top: 0, left: 0, bottom: 34, right: 84) window.safeAreaInsets = (top: 0, left: 0, bottom: 34, right: 84) occlusion reserved region (active): (385, 0, 84, 120) right 22: (410, 120, 22, 515) right 44: (399, 120, 44, 515) right 88: (377, 120, 88, 515) top 22: (8.67, 37, 376.33, 22) With a leading bar there is no active occlusion region for the status bar, and the window has no leading inset, yet UINavigationController adds one. Sample project
Topic: UI Frameworks SubTopic: UIKit
Replies
3
Boosts
2
Views
155
Activity
2d
How to separate/add space between Liquid Glass toolbar items when using ToolbarOverflowMenu
When optimizing for iPhone Duo (and in general) I understand the recommendation is to replace custom More (...) menus with the system overflow menu, otherwise it's possible you can see two (...) buttons or get the custom menu nested inside the system overflow menu. Eek. With the following code, both (+) and (...) are unexpectedly inside one shared Liquid Glass background. How do you separate / add space between them or is this a bug, if so is there a workaround? struct ContentView: View { var body: some View { NavigationStack { Text("Hello, World") .toolbar { ToolbarItem { Button("Add", systemImage: "plus") { } } ToolbarSpacer(.fixed) ToolbarOverflowMenu { Button("Settings", systemImage: "gearshape") { } } } } } } Here's my original code that display two separate buttons as expected: struct ContentView: View { var body: some View { NavigationStack { Text("Hello, World") .toolbar { ToolbarItem { Button("Add", systemImage: "plus") { } } ToolbarSpacer(.fixed) ToolbarItem { Menu { Button("Settings", systemImage: "gearshape") { } } label: { Label("More", systemImage: "ellipsis") } } } } } } Why do I care you might ask? When the user turns on filters in my app, a filter toolbar item is shown, and I want the (+) to remain separate from the grouped filter and more buttons. (+) is like the primary action that should stand alone, like it does in the Wallet app.
Topic: UI Frameworks SubTopic: SwiftUI
Replies
3
Boosts
1
Views
98
Activity
2d