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 WWDC25 Group Lab - UI Frameworks
At WWDC25 we launched a new type of Lab event for the developer community - Group Labs. A Group Lab is a panel Q&A designed for a large audience of developers. 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 WWDC25 Group Lab for UI Frameworks. How would you recommend developers start adopting the new design? Start by focusing on the foundational structural elements of your application, working from the "top down" or "bottom up" based on your application's hierarchy. These structural changes, like edge-to-edge content and updated navigation and controls, often require corresponding code modifications. As a first step, recompile your application with the new SDK to see what updates are automatically applied, especially if you've been using standard controls. Then, carefully analyze where the new design elements can be applied to your UI, paying particular attention to custom controls or UI that could benefit from a refresh. Address the large structural items first then focus on smaller details is recommended. Will we need to migrate our UI code to Swift and SwiftUI to adopt the new design? No, you will not need to migrate your UI code to Swift and SwiftUI to adopt the new design. The UI frameworks fully support the new design, allowing you to migrate your app with as little effort as possible, especially if you've been using standard controls. The goal is to make it easy to adopt the new design, regardless of your current UI framework, to achieve a cohesive look across the operating system. What was the reason for choosing Liquid Glass over frosted glass, as used in visionOS? The choice of Liquid Glass was driven by the desire to bring content to life. The see-through nature of Liquid Glass enhances this effect. The appearance of Liquid Glass adapts based on its size; larger glass elements look more frosted, which aligns with the design of visionOS, where everything feels larger and benefits from the frosted look. What are best practices for apps that use customized navigation bars? The new design emphasizes behavior and transitions as much as static appearance. Consider whether you truly need a custom navigation bar, or if the system-provided controls can meet your needs. Explore new APIs for subtitles and custom views in navigation bars, designed to support common use cases. If you still require a custom solution, ensure you're respecting safe areas using APIs like SwiftUI's safeAreaInset. When working with Liquid Glass, group related buttons in shared containers to maintain design consistency. Finally, mark glass containers as interactive. For branding, instead of coloring the navigation bar directly, consider incorporating branding colors into the content area behind the Liquid Glass controls. This creates a dynamic effect where the color is visible through the glass and moves with the content as the user scrolls. I want to know why new UI Framework APIs aren’t backward compatible, specifically in SwiftUI? It leads to code with lots of if-else statements. Existing APIs have been updated to work with the new design where possible, ensuring that apps using those APIs will adopt the new design and function on both older and newer operating systems. However, new APIs often depend on deep integration across the framework and graphics stack, making backward compatibility impractical. When using these new APIs, it's important to consider how they fit within the context of the latest OS. The use of if-else statements allows you to maintain compatibility with older systems while taking full advantage of the new APIs and design features on newer systems. If you are using new APIs, it likely means you are implementing something very specific to the new design language. Using conditional code allows you to intentionally create different code paths for the new design versus older operating systems. Prefer to use if #available where appropriate to intentionally adopt new design elements. Are there any Liquid Glass materials in iOS or macOS that are only available as part of dedicated components? Or are all those materials available through new UIKit and AppKit views? Yes, some variations of the Liquid Glass material are exclusively available through dedicated components like sliders, segmented controls, and tab bars. However, the "regular" and "clear" glass materials should satisfy most application requirements. If you encounter situations where these options are insufficient, please file feedback. If I were to create an app today, how should I design it to make it future proof using Liquid Glass? The best approach to future-proof your app is to utilize standard system controls and design your UI to align with the standard system look and feel. Using the framework-provided declarative API generally leads to easier adoption of future design changes, as you're expressing intent rather than specifying pixel-perfect visuals. Pay close attention to the design sessions offered this year, which cover the design motivation behind the Liquid Glass material and best practices for its use. Is it possible to implement your own sidebar on macOS without NSSplitViewController, but still provide the Liquid Glass appearance? While technically possible to create a custom sidebar that approximates the Liquid Glass appearance without using NSSplitViewController, it is not recommended. The system implementation of the sidebar involves significant unseen complexity, including interlayering with scroll edge effects and fullscreen behaviors. NSSplitViewController provides the necessary level of abstraction for the framework to handle these details correctly. Regarding the SceneDelagate and scene based life-cycle, I would like to confirm that AppDelegate is not going away. Also if the above is a correct understanding, is there any advice as to what should, and should not, be moved to the SceneDelegate? UIApplicationDelegate is not going away and still serves a purpose for application-level interactions with the system and managing scenes at a higher level. Move code related to your app's scene or UI into the UISceneDelegate. Remember that adopting scenes doesn't necessarily mean supporting multiple scenes; an app can be scene-based but still support only one scene. Refer to the tech note Migrating to the UIKit scene-based life cycle and the Make your UIKit app more flexible WWDC25 session for more information.
Topic: UI Frameworks SubTopic: General
0
0
738
Jun ’25
UITabbarController - padOS18: at top, padOS17 and before: at Bottom
This pertains to iPad apps and UITabbarController in UIKit. Our internal app for employees utilizes UITabbarController displayed at the bottom of the screen. Users prefer to maintain consistency with it being at the bottom. It becomes challenging to argue against this when users point out the iPhone version displaying it "correctly" at the bottom. My response is to trust Apple's design team to keep it at the top. One workaround is to develop the app using the previous Xcode version, version 15 (via Xcode Cloud), targeting padOS17. This ensures the tab bar is shown at the bottom of the screen. However, this approach has its drawbacks: Apple may not support it in the future, leading to missed secure updates for the app, among other issues. Exploring the UITabbarController mode appears to be the solution I am seeking. To quote the documentation "on iPad, If the tabs array contains one or more UITabGroup items, the system displays the content as either a tab bar or a sidebar, depending on the context. Otherwise, it only displays the content only as a tab bar.". The part "displays the content only as a tab bar." made think this is BAU: class ViewController: UITabBarController { override func viewDidLoad() { super.viewDidLoad() self.mode = .tabBar } } Unfortunately, this does not resolve the issue. Is there an API method that can force the tabbar to its previous bottom position? The app uses multiple windows. When we split a window to launch another instance, the tab bar appears at the bottom. This behavior seems tied to the form factor—or potentially to how many items are in the tab bar. We could build a custom tab bar to override this, but that goes against my “don’t reinvent the wheel” principle. Any comments we welcome and thank you for reading this (to the end) Theo
1
0
489
Feb ’25
MKGeoJSONDecoder and Single Points
https://developer.apple.com/documentation/mapkit/mkgeojsondecoder?changes=__9&language=objc I am trying to use this decoder to obtain single points form a geojson file. I am able to do this successfully however, when using MapKit for iOS 17+ I am unable to use a ForEach to iterate through these points (stored in an array) and display these on the map as a custom annotation or even a marker. MapAnnotation(coordinate: point.coordinate) { VStack { Image(systemName: "mappin.circle.fill") .resizable() .frame(width: 25, height: 25) .foregroundColor(.purple) if let title = point.title { Text(title) .font(.caption) .foregroundColor(.purple) .padding(2) .background(Color.white.opacity(0.8)) .cornerRadius(3) } } }
1
0
250
Mar ’25
Difficulty Localizing App Display Name Based on Region in iOS.
I have an application named "XY" that has been launched in several countries. Now, I intend to launch it in Turkey, but we are facing legal issues preventing us from using "XY" as the app's display name. Following the documentation, I localized the app's display name to "ZX" for both Turkish and English (Turkey). However, when users change their device settings, they do not see an option for English (Turkey) language selection. I assumed that for Turkish users, English (Turkey) would be the default language, but this is not the case. Could someone please assist me in resolving this issue? I've investigated options for localizing the display name based on region, but it seems that this functionality isn't feasible on iOS. In contrast, it's relatively straightforward to achieve on Android platforms.
0
0
452
Mar ’25
WKWebView: Select Text and scroll beyond what's visible
Prime Objective I am trying to have a scroll view with a fixed header, a fixed footer, and a WKWebView in between. Using JavaScript, the height of the webView is determined and set to be large enough to hold the entire content. The Problem When selecting text on the webView, the view does not scroll when the edges are reached (this works if the webView is shown without being embedded in a Scroll view, or if it is the last element) What did I try? I tried reading the scroll view, or adding a gesture recognizer, but all of that does not work because the selection is essentially a system task Sourcecode Sourcecode to demonstrate the issue can be found on GitHub
1
0
352
Mar ’25
macOS Menu disappears when converting from NSApplicationActivationPolicyAccessory to NSApplicationActivationPolicyRegular if display disconnected and reconnected
I'm not quite sure where the problem is, but I will describe what I am doing to recreate the issue, and am happy to provide whatever information I can to be more useful. I am changing the ActivationPolicy for my app in order to make it unobtrusive when in the background (e.g. hiding it from the dock and using only a menu bar status item). When the user activates the app with a hotkey, it changes from NSApplicationActivationPolicyAccessory back to NSApplicationActivationPolicyRegular. This allows normal usage (dock icon, menu bar, etc.) This works fine, except in a rare situation which I finally just tracked down. If there is a window open in the app and I use the hotkey to convert back to an accessory, and then disconnect and reconnect the display on which the app was previously displayed, when I convert the app back to "regular mode", the menu bar has disappeared (and I am left with an empty space at the top of the screen). I can also trigger this bug by having the display in question briefly mirror the other display (effectively "orphaning" the hidden app), and then restoring the original side-by-side configuration before activating the app again. The app otherwise works, but the menu bar is missing. Switching back and forth with other apps does not fix the problem. Quitting and restarting the app resolves the issue. As does disabling the accessory only mode and forcing the app to always remain in "regular mode" with a dock icon (there is a preference for this in my app). Once fixed, I can then re-enable the "accessory mode" and all is well until the bug is triggered again. The bug would normally occur quite sporadically, presumably requiring a particular combination of changing Spaces or displays, or having the computer go to sleep while this app was in accessory mode. Thus far, the above is the only way I have found that can replicate this issue on demand. If I close all windows before hiding the app, then it works fine when I revert to "regular mode". It only happens if there is a window open at the time. Using applicationDidChangeScreenParameters: on my AppDelegate indicates that there is a change in screen, and logging window.screen.frame for each open window in [NSApp orderedWindows] shows that the size changes from e.g. 1920x1080 to 0x0 and back while the display is disconnected or mirrored. There is also an error in the console in Xcode when this happens -- invalid display identifier <some UUID>. I have tried various options for window collectionBehavior, as well as various settings for Spaces (which I normally use). None of these changes has fixed the behavior thus far. I use [NSApp hide:self]; from my AppDelegate to hide the app, and [[NSRunningApplication currentApplication] activateWithOptions:NSApplicationActivateAllWindows];[NSApp unhide:self]; to bring it back to the front. I welcome any ideas for things to chase down, or requests for more specific information that would be useful. Thank you! Fletcher
1
0
466
Feb ’25
Adding Markdown support in notes app
Hi guys, I’m making a simple note taking app and I want to support markdown functionality. I have tried to find libraries and many other GitHub repos but some of them are slow and some of them are very hard to implement and not very customizable. In WWDC 22 apple also made a markdown to html document app and I also looked at that code and it was awesome. It was fast and reliable (Apple btw). But the only problem I am facing is that the markdown text is on the left side and the output format is on the right in the form of html. I don’t want that I want both in the same line. In bear notes and things 3 you can write in markdown and you can see that it is converting in the same line. I have also attached example videos. So, I have markdown parser by apple but the only thing in the way is that it is converting it into a html document. Please help me with this. Also please look into the things 3 video they have also completely customized the text attributes selection menu. By default with UITextView we can only enable text attributes and it shows like this. By clicking more we get the complete formatting menu but not the slider menu which is more convenient. Please also help me this. I don’t know if I can provide apple file but it is from wwdc 22 supporting desktop class interaction
0
0
385
Feb ’25
SwiftUI @Observable Causes Extra Initializations When Using Reference Type Properties
I've encountered an issue where using @Observable in SwiftUI causes extra initializations and deinitializations when a reference type is included as a property inside a struct. Specifically, when I include a reference type (a simple class Empty {}) inside a struct (Test), DetailsViewModel is initialized and deinitialized twice instead of once. If I remove the reference type, the behavior is correct. This issue does not occur when using @StateObject instead of @Observable. Additionally, I've submitted a feedback report: FB16631081. Steps to Reproduce Run the provided SwiftUI sample code (tested on iOS 18.2 & iOS 18.3 using Xcode 16.2). Observe the console logs when navigating to DetailsView. Comment out var empty = Empty() in the Test struct. Run again and compare console logs. Change @Observable in DetailsViewModel to @StateObject and observe that the issue no longer occurs. Expected Behavior The DetailsViewModel should initialize once and deinitialize once, regardless of whether Test contains a reference type. Actual Behavior With var empty = Empty() present, DetailsViewModel initializes and deinitializes twice. However, if the reference type is removed, or when using @StateObject, the behavior is correct (one initialization, one deinitialization). Code Sample import SwiftUI enum Route { case details } @MainActor @Observable final class NavigationManager { var path = NavigationPath() } struct ContentView: View { @State private var navigationManager = NavigationManager() var body: some View { NavigationStack(path: $navigationManager.path) { HomeView() .environment(navigationManager) } } } final class Empty { } struct Test { var empty = Empty() // Comment this out to make it work } struct HomeView: View { private let test = Test() @Environment(NavigationManager.self) private var navigationManager var body: some View { Form { Button("Go To Details View") { navigationManager.path.append(Route.details) } } .navigationTitle("Home View") .navigationDestination(for: Route.self) { route in switch route { case .details: DetailsView() .environment(navigationManager) } } } } @MainActor @Observable final class DetailsViewModel { var fullScreenItem: Item? init() { print("DetailsViewModel Init") } deinit { print("DetailsViewModel Deinit") } } struct Item: Identifiable { let id = UUID() let value: Int } struct DetailsView: View { @State private var viewModel = DetailsViewModel() @Environment(NavigationManager.self) private var navigationManager var body: some View { ZStack { Color.green Button("Show Full Screen Cover") { viewModel.fullScreenItem = .init(value: 4) } } .navigationTitle("Details View") .fullScreenCover(item: $viewModel.fullScreenItem) { item in NavigationStack { FullScreenView(item: item) .navigationTitle("Full Screen Item: \(item.value)") .toolbar { ToolbarItem(placement: .cancellationAction) { Button("Cancel") { withAnimation(completionCriteria: .logicallyComplete) { viewModel.fullScreenItem = nil } completion: { var transaction = Transaction() transaction.disablesAnimations = true withTransaction(transaction) { navigationManager.path.removeLast() } } } } } } } } } struct FullScreenView: View { @Environment(\.dismiss) var dismiss let item: Item var body: some View { ZStack { Color.red Text("Full Screen View \(item.value)") .navigationTitle("Full Screen View") } } } Console Output With var empty = Empty() in Test DetailsViewModel Init DetailsViewModel Init DetailsViewModel Deinit DetailsViewModel Deinit Without var empty = Empty() in Test DetailsViewModel Init DetailsViewModel Deinit Using @StateObject Instead of @Observable DetailsViewModel Init DetailsViewModel Deinit Additional Notes This issue occurs only when using @Observable. Switching to @StateObject prevents it. This behavior suggests a possible issue with how SwiftUI handles reference-type properties inside structs when using @Observable. Using a struct-only approach (removing Empty class) avoids the issue, but that’s not always a practical solution. Questions for Discussion Is this expected behavior with @Observable? Could this be an unintended side effect of SwiftUI’s state management? Are there any recommended workarounds apart from switching to @StateObject? Would love to hear if anyone else has run into this or if Apple has provided any guidance!
0
0
341
Feb ’25
SwiftUI Transformable: support drag to Finder on macOS
I am trying to support dragging out a 'file' object from my app into Finder, on macOS. I have my object conform to Transferable and the files are saved on disk locally, so I just want to pass it the URL. This works fine when dragging out to other apps, like Notes or Mail, but not in Finder. I setup a ProxyRepresentation as well, as suggested by another thread, but it doesn't seem to help. Is there any other setup I need to do in the Xcode project file for it to work, or is there something else that I'm missing? @available(iOSApplicationExtension 17.0, macOSApplicationExtension 14.0, *) extension FileAttachments: Transferable { public static var transferRepresentation: some TransferRepresentation { FileRepresentation(exportedContentType: UTType.content) { content in SentTransferredFile(content.fullFileURL(), allowAccessingOriginalFile: false) } .exportingCondition { file in if let fileUTI = UTType(filenameExtension: file.fullFileURL().pathExtension), let fileURL = file.fullFileURL() { print("FileAttachments: FileRepresentation exportingCondition fileUTI: \(fileUTI) for file: \(fileURL)") return fileUTI.conforms(to: UTType.content) } return false } .suggestedFileName{$0.fileRenamedName} ProxyRepresentation { file in if let fileURL = file.fullFileURL() { print("FileAttachments: ProxyRepresentation returning file") return fileURL } return file.fullFileURL()! } } }
1
0
385
Feb ’25
How to initialize @Observable object in View via @State?
When I switched to observable, I noticed a strange behavior of the ViewModel. The ViewModel is created 3x times. And my question is: How to properly initialize the ViewModel via state? Below is a minimal example with log output: ViewModel INIT : EBBB2C41 ViewModel INIT : D8E490DA ViewModel INIT : 54407300 ViewModel DEINIT: D8E490DA @Observable final class ViewModel { @ObservationIgnored let idd: UUID init() { idd = UUID() print("ViewModel INIT : \(idd.uuidString.prefix(8))") } deinit { print("ViewModel DEINIT: \(idd.uuidString.prefix(8))") } } struct SimpleView: View { @Environment(ViewModel.self) private var viewModel var body: some View { @Bindable var viewModel = viewModel Text("SimpleView: \(viewModel.idd.uuidString.prefix(8))") } } struct ContentView: View { @State private var viewModel = ViewModel() var body: some View { SimpleView() .environment(mainViewModel) } }
1
0
443
Feb ’25
Extending iOS screen to an external display
I understand two key concepts from desktop platforms: Screen Mirroring – The same content is displayed on both the primary and external screens. Screen Extension – The external display shows different content that complements what's on the main screen. My question pertains to the second point: Is it possible to extend the display on iOS and iPadOS devices? I'm referring to this Apple documentation, which explains how to extend content from an iOS/iPadOS device to an external display. I tested this in a sample iOS Xcode project. In the iOS Simulator, I was able to detect an "external display" and present a separate UIWindow on it. However, when I tried the same on a real device (iPhone 15 connected to a MacBook Pro via cable), the external display connection was not detected. I’d like to confirm whether screen extension is possible on a real iOS device. From my research, it appears that extension is only supported on iPadOS via Stage Manager, but I want to verify if there’s any way to achieve this on an iPhone. If so, are there any known apps that currently utilize extended display functionality on iOS? If extension is not possible on iOS, what does the documentation mentions iOS?
1
0
571
Feb ’25
Data fetching issue from SensorKit
I want SensorKit data for research purposes in my current application. I have applied for and received permission from Apple to access SensorKit data. During implementation, I encountered an issue in which no data was being retrieved despite granting all the necessary permissions. I am using did CompleteFetch & didFetchResult delegate methods for retrieving data from Sensorkit. CompleteFetch method calls but where I can find different event data like Device usage, Ambient Light, etc? & didFetchResult method does not call. Methods I am using: 1. func sensorReader(_ reader: SRSensorReader, didCompleteFetch fetchRequest: SRFetchRequest) 2. func sensorReader(_ reader: SRSensorReader, fetching fetchRequest: SRFetchRequest, didFetchResult result: SRFetchResult<AnyObject>) -> Bool Could anyone please assist me in resolving this issue? Any guidance or troubleshooting steps would be greatly appreciated.
0
0
376
Feb ’25
SwiftUI: How do you do CoreData backup and restore?
Hi, I am trying to create a local backup + restore when using SwiftUI and CoreData but I am facing errors left and right. the latest error I am stuck on is: *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'executeFetchRequest:error: A fetch request must have an entity.' Here is what am trying to do: Creating a backup (already solved using NSPersistentStoreCoordinator.migratePersistentStore(_:to:options:type:)) Create a new NSPersistentContainer and call its NSPersistentContainer.loadPersistentStores(completionHandler:) (already solved, load is successful) Update the .environment(.managedObjectContext, viewModel.context) so that SwiftUI uses the new context. (HERE is where the error appears) Any help would be appreciated. Here is some sample code of SwiftUI part of the main view: class ViewModel: ObservableObject { @Published var context: NSManagedObjectContext } @main struct MyApp: App { @StateObject var viewModel: ViewModel var body: some Scene { WindowGroup { ContentView() .environment(\.managedObjectContext, viewModel.context) } } }
Topic: UI Frameworks SubTopic: SwiftUI
0
0
243
Mar ’25
LazyHstack in SwiftUI not supporting varying height views
In SwiftUI I want to create a list with LazyVstack and each row item in the LazyVstack is a LazyHstack of horizontally scrollable list of images with some description with line limit of 3 and width of every item is fixed to 100 but height of every item is variable as per description text content. But in any of the rows if the first item has image description of 1 line and the remaining items in the same row has image description of 3 lines then the LazyHStack is truncating all the image descriptions in the same row to one line making all the items in that row of same height. Why LazyHStack is not supporting items of varying height ? Expected behaviour should be that height of every LazyHStack should automatically adjust as per item content height. But it seems SwiftUI is not supporting LazyHstack with items of varying height. Will SwiftUI ever support this feature?
Topic: UI Frameworks SubTopic: SwiftUI
0
0
267
Feb ’25
UITabbarController issue on iOS 18
I'm building an app using UITabbarController with 2 tabs: screen A and B. When standing on tab B and I taps on tab A, the order in which the events are triggered will be: For iOS < 18: viewWillDisappear() of screen B tabBarController(_:didSelect:) of UITabbarController For iOS >= 18: tabBarController(_:didSelect:) of UITabbarController viewWillDisappear() of screen B So my question is this an issue or a new update from Apple on iOS 18.*?
Topic: UI Frameworks SubTopic: UIKit Tags:
2
0
391
Mar ’25
Button Behavior between fullScreenCover and sheet
The behavior of the Button in ScrollView differs depending on how the View is displayed modally. When the View is displayed as a .fullScreenCover, if the button is touched and scrolled without releasing the finger, the touch event is canceled and the action of the Button is not called. On the other hand, if the View is displayed as a .sheet, the touch event is not canceled even if the view is scrolled without lifting the finger, and the action is called when the finger is released. In order to prevent accidental interaction, I feel that the behavior of .fullScreenCover is better, as it cancels the event immediately when scrolling. Can I change the behavior of .sheet? Demo movie is here: https://x.com/kenmaz/status/1896498312737611891 Sample code import SwiftUI @main struct SampleApp: App { var body: some Scene { WindowGroup { ContentView() } } } struct ContentView: View { @State private var showSheet = false @State private var showFullScreen = false var body: some View { VStack(spacing: 16) { Button("Sheet") { showSheet.toggle() } Button("Full screen") { showFullScreen.toggle() } } .sheet(isPresented: $showSheet) { SecondView() } .fullScreenCover(isPresented: $showFullScreen) { SecondView() } .font(.title) } } struct SecondView: View { @Environment(\.dismiss) var dismiss var body: some View { ScrollView { Button("Dismiss") { dismiss() } .buttonStyle(MyButtonStyle()) .padding(.top, 128) .font(.title) } } } private struct MyButtonStyle: ButtonStyle { func makeBody(configuration: Self.Configuration) -> some View { configuration .label .foregroundStyle(.red) .background(configuration.isPressed ? .gray : .clear) } }
Topic: UI Frameworks SubTopic: SwiftUI
0
0
189
Mar ’25
Hover effect is shown on a disabled button
Hello. I have a scenario where a hover effect is being shown for a button that is disabled. Usually this doesn't happen but when you wrap the button in a Menu it doesn't work properly. Here is some example code: struct ContentView: View { var body: some View { NavigationStack { Color.green .toolbar { ToolbarItem(placement: .topBarTrailing) { Menu("Menu") { Button("Disabled Button") {} .disabled(true) .hoverEffectDisabled() // This doesn't work. Button("Enabled Button") {} } } } } } } And here is what it looks like: This looks like a SwiftUI bug. Any help is appreciated, thank you!
1
0
267
Feb ’25
List does not move the view into focused element, when changing it with a keyboard
Here is a simple main.swift file of a macOS app: import SwiftUI struct ContentView: View { @State private var selectedItem = 0 @FocusState private var isListFocused: Bool var body: some View { List(0..<40, id: \.self, selection: $selectedItem) { index in Text("\(index)") .padding() .focusable() } .focused($isListFocused) .onAppear { isListFocused = true } } } func createAppWindow() { let window = NSWindow( contentRect: .zero, styleMask: [.titled], backing: .buffered, defer: false ) window.contentViewController = NSHostingController(rootView: ContentView()) window.setContentSize(NSSize(width: 759, height: 300)) window.center() window.makeKeyAndOrderFront(nil) } class AppDelegate: NSObject, NSApplicationDelegate { func applicationDidFinishLaunching(_ notification: Notification) { createAppWindow() } } let delegate = AppDelegate() NSApplication.shared.delegate = delegate NSApplication.shared.run() Try to move the focus with a keyboard slowly as shown on the GIF attached and you'll see that the focus items don't sit in a List's view.
2
0
305
Mar ’25
On macOS SwiftUI.TimelineView() inside NSViewController is causing AutoLayout recalculations
I have a complex app that requires the main SwiftUI view of the app to be embedded inside an NSHostingView which is a subview of an NSViewController's view. Then this NSViewController is wrapped using NSViewControllerRepresentable to be presented using SwiftUI's Window. And if I have a TimelineView inside my SwiftUI view hierarchy, it causes constant recalculation of the layout. Here's a simplified demo code: @main struct DogApp: App { private let dogViewController = DogViewController() var body: some Scene { Window("Dog", id: "main") { DogViewControllerUI() } } } private struct DogViewControllerUI: NSViewControllerRepresentable { let dogViewController = DogViewController () func makeNSViewController(context: Context) -> NSViewController { dogViewController } func updateNSViewController(_ nsViewController: NSViewController, context: Context) {} func sizeThatFits(_ proposal: ProposedViewSize, nsViewController: NSViewController, context: Context) -> CGSize? { debugPrint("sizeThatFits", proposal) return nil } } public class DogViewController: NSViewController { public override func viewDidLoad() { super.viewDidLoad() let mainView = MainView() let hostingView = NSHostingView(rootView: mainView) view.addSubview(hostingView) hostingView.translatesAutoresizingMaskIntoConstraints = false hostingView.topAnchor.constraint(equalTo: view.topAnchor).isActive = true hostingView.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true hostingView.trailingAnchor.constraint(equalTo: view.trailingAnchor).isActive = true hostingView.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true } } struct MainView: View { var body: some View { VStack { TimelineView(.animation) { _ in Color.random .frame(width: 100, height: 100) } } } } extension Color { static var random: Color { Color( red: .random(in: 0...1), green: .random(in: 0...1), blue: .random(in: 0...1) ) } } When running it's printing out this repeatedly (multiple times a second). "sizeThatFits" SwiftUI.ProposedViewSize(width: Optional(559.0), height: Optional(528.0)) "sizeThatFits" SwiftUI.ProposedViewSize(width: Optional(0.0), height: Optional(0.0)) "sizeThatFits" SwiftUI.ProposedViewSize(width: Optional(559.0), height: Optional(528.0)) "sizeThatFits" SwiftUI.ProposedViewSize(width: Optional(0.0), height: Optional(0.0)) "sizeThatFits" SwiftUI.ProposedViewSize(width: Optional(559.0), height: Optional(528.0)) "sizeThatFits" SwiftUI.ProposedViewSize(width: Optional(0.0), height: Optional(0.0)) "sizeThatFits" SwiftUI.ProposedViewSize(width: Optional(559.0), height: Optional(528.0)) If I run an equivalent code for an iPad, it only prints twice. If I comment out TimelineView on macOS, then it only prints out the above logs when resizing the app window. The main reason this is an issue is that it's clearly causing dramatic degradation in performance. I was told to submit a bug report after I submitted TSI so a SwiftUI engineer could investigate it. Case-ID: 7461887. FB13810482. This was back in May but I received no response. LLMs are no help, and I've experimented with all sorts of workarounds. My last hope is this forum, maybe someone has an idea of what might be going on and why the recalculation is happening constantly on macOS.
1
0
389
Feb ’25