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

Created

Do SwiftUI Segmented Controls on macOS 26 support the icon and title label style?
On macOS 26.3, Xcode 26.3, why does a labelStyle of titleAndIcon not show both the title and the icon of a label? The label styles iconOnly and titleOnly behave as expected. Picker("Label Demo", selection: $selectedItem) { Label { Text("File") } icon: { Image(systemName: "doc") } Label { Text("Folder") } icon: { Image(systemName: "folder") } } .labelStyle(.titleAndIcon) .pickerStyle(.segmented) Note that there is no icon shown. Placing the .labelStyle modifier in different places has no effect. The icon is correctly shown when the labelStyle is set to .iconOnly. An NSSegmentedControl created with AppKit and presented in an NSViewRepresentable does correctly show titles and icons if configured appropriately. Tested on: macOS 26.3 (25D125) Xcode 26.3 (17C519) A brand new SwiftUI "macOS App" project.
2
0
47
3d
How to delete a row from a table
To display rows and columns of data in a nice layout like a spreadsheet I use a table like the code here .. Table(array) { TableColumn("Ticker", value: \\.ticker) TableColumn("Other", value: \.other) } To delete a row from the table the advice is to use a ForEach loop. Since I don’t use a ForEach loop, how do I delete rows from the table ? With this code there is no way to attach a .onDelete modifier or a Button Any advice would be much appreciated Thank you
Topic: UI Frameworks SubTopic: SwiftUI
1
0
34
4d
Does anyone know how to prevent Liqud Glass from stretching when elements with the glassEffect are dragged?
When making an element with .glassEffect(.clear.interactive()) draggable, it stretches as it moves. It seems like it's meant to stretch as you move your finger away from the element, but it doesn't make sense if the element is following your finger as you drag it. Is this a bug, or is there a way to disable this behavior without removing the other "interactive" animations? P.S. The shiny border around the elements seems to be a rounded rectangle or capsule, but the actual element's shape seems to be stretched. That also appears to be a bug.
0
0
47
5d
How does NSTextView invoke grammar checking internally
I'm building a macOS app that uses WKWebView for text editing (not NSTextView). I need to provide grammar checking by calling NSSpellChecker programmatically and sending results back to the web editor. The problem: TextEdit (which uses NSTextView) catches grammar errors like "Can I has pie?" and "These are have" — but when I call NSSpellChecker's APIs directly, those same errors are never flagged. I've tried both APIs: 1. The unified check() API: let results = checker.check( text, range: range, types: NSTextCheckingAllTypes, options: [:], inSpellDocumentWithTag: tag, orthography: &orthography, wordCount: &wordCount) This returns only .orthography results (language detection). No .spelling, no .grammar — just orthography. 2. The dedicated checkGrammar(of:startingAt:...) API: let sentenceRange = checker.checkGrammar( of: text, startingAt: offset, language: nil, wrap: false, inSpellDocumentWithTag: tag, details: &details) This catches sentence fragments ("The.", "No.") and some agreement errors ("The is anyone.") but misses "Can I has pie?", "These are have", "This will be happened", and other subject-verb agreement errors that TextEdit highlights. What I've confirmed: "Check Grammar With Spelling" is enabled in System Settings TextEdit reliably catches all these errors with green underlines Both APIs are called with a valid spellDocumentTag from uniqueSpellDocumentTag() The text is passed as plain strings (no attributed string context) My question: How does NSTextView's grammar checking work internally? It must be using something beyond these two public APIs. Possibilities I'm considering: Does NSTextView use the NSTextCheckingClient protocol / requestChecking(of:range:types:options:) for asynchronous checking that produces different results? Does NSTextView provide additional context (attributed string, layout info) that improves grammar detection? Is there a private/undocumented API or framework that NSTextView uses for deeper grammar analysis? Any insight from anyone who has implemented programmatic grammar checking on macOS would be appreciated. NOTE: This post was composed with the help of Claude Code, which I am using to help write a word-processing application, but I am frustrated because Claude Code wants to give up and switch to a 3rd party grammar checker, like LanguageTool, and it seems to me that it should be possible to use native Apple tools to achieve this goal without requiring the user to send their data elsewhere for checking. I've spent a lot of time searching the web for answers and have found surprisingly little on this. Any pointers people might have would be very much appreciated! Thanks.
0
0
37
5d
iOS 26.3: Memory crash with @AppStorage and view transitions
I'm experiencing consistent memory crashes in iOS 26.3 (23D127) when using @AppStorage with view transitions. Environment: Device: iPhone 17 Pro Max iOS: 26.3 (23D127) Xcode: 26.2 (17C52) Issue: App crashes with "Terminated due to memory issue" when: Using @AppStorage to manage state Calling UserDefaults.set() in completion handler Transitioning to new view based on changed state Workaround: Using @State instead of @AppStorage prevents crash. Feedback: FB############ (your number) Has anyone else experienced this? Is this a known issue in iOS 26?
Topic: UI Frameworks SubTopic: SwiftUI
0
0
33
6d
Does Liquid Glass ignore regular hit testing in SwiftUI?
I’ve encountered an aspect of the Liquid Glass effect in SwiftUI that seems a bit odd: the Liquid Glass interaction appears to ignore regular hit-testing behavior. The following sample shows a button with hit testing disabled: @main struct LiquidGlassHitTestDemo: App { var body: some Scene { WindowGroup { Button("Liquid") { fatalError("Never called.") } .buttonStyle(.glassProminent) .allowsHitTesting(false) } } } As expected, the button’s action is never called. However, the interactive glass effect still responds to touch events: What’s even more surprising is that the UIKit equivalent behaves differently: final class ViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() let button = UIButton( configuration: .prominentGlass(), primaryAction: UIAction( title: "Liquid", handler: { action in print("Never called.") } ) ) view.addSubview(button) button.translatesAutoresizingMaskIntoConstraints = false NSLayoutConstraint.activate([ button.centerXAnchor.constraint(equalTo: view.centerXAnchor), button.centerYAnchor.constraint(equalTo: view.centerYAnchor) ]) button.isUserInteractionEnabled = false } } In this case, the effect is not interactive at all. Similarly, if a UIViewController’s root view overrides hitTest(_:with:) to always return nil, the Liquid Glass effect does not react to touch events whatsoever. The only way I’ve found to “properly” disable the glass interactivity in SwiftUI is to use the .disabled(true) modifier. However, this also changes the button’s appearance, which is not always desirable. Is this expected behavior, or could this be a bug? Am I missing something about how Liquid Glass interaction is implemented in SwiftUI?
0
2
51
6d
Testing a locale with space as thousands separator and dot as decimal point
MacOS system settings allow the user to select one of a number of number formats. My app behaves differently depending on the format (taken from the system Locale), so I need to test every combination. Thus far I have been successful at creating Locale objects with various identifiers that map to the different formats, like: let westEuropeanLocale = Locale(identifier: "en_DE") However, I can't find a locale that maps to using . as a decimal point, and space as a thousands separator, even though it's a standard option (3rd in this list): Any suggestions on how to create a test for this number format?
1
0
84
6d
iMessage Extension: didSelect not called when tapping message bubbles on iPad
I'm developing a turn-based Messages game extension and experiencing a persistent issue on iPad where tapping on message bubbles does not reliably trigger lifecycle callbacks after the extension has been used once. The Problem: On iPad, after a player: Opens the extension by tapping a game message Takes their turn (plays a card) Sends the updated game state as a new message Extension collapses When the opponent sends their response and the player taps on the new message bubble, the extension often does not open. The didSelect(_:conversation:) method is not called. The user must refresh the conversation by scrolling away and back or reopening the Messages App before tapping works again. This works perfectly on iPhone - every tap on a message bubble reliably triggers didSelect and opens the extension. What I've Tried: I've implemented every lifecycle method and workaround I could find: swiftoverride func willBecomeActive(with conversation: MSConversation) { super.willBecomeActive(with: conversation) if let message = conversation.selectedMessage, let url = message.url { loadGameState(from: url, message: message, conversation: conversation) } } override func didBecomeActive(with conversation: MSConversation) { super.didBecomeActive(with: conversation) if let message = conversation.selectedMessage, let url = message.url { loadGameState(from: url, message: message, conversation: conversation) } } override func didSelect(_ message: MSMessage, conversation: MSConversation) { // This is NOT called on iPad when tapping message bubbles guard let url = message.url else { return } loadGameState(from: url, message: message, conversation: conversation) } override func didReceive(_ message: MSMessage, conversation: MSConversation) { guard let url = message.url else { return } loadGameState(from: url, message: message, conversation: conversation) } override func didTransition(to presentationStyle: MSMessagesAppPresentationStyle) { super.didTransition(to: presentationStyle) // Attempted to reload here as well } I also tried: Observing NSExtensionHostDidBecomeActive and NSExtensionHostWillEnterForeground notifications Forcing UI refresh in viewDidLayoutSubviews Checking conversation.selectedMessage in every lifecycle method Research: I found several Developer Forums threads from 2016 describing this exact issue: Thread 53167: "MSMessagesAppViewController.didSelect not called on message reselect" Thread 60323: "willSelectMessage and didSelectMessage don't fire" An Apple staff member confirmed that didSelect only fires when selecting a different message, similar to UITableView selection behavior. However, on iPad, it seems like messages remain "selected" even after the extension collapses, so tapping a new message doesn't register as a new selection. Questions: Is there a recommended way to detect when a user taps a message bubble on iPad, even if iOS considers a message "already selected"? Is there a way to programmatically deselect the current message (similar to UITableView.deselectRow) so that subsequent taps trigger didSelect? Are there any iPad-specific lifecycle methods or notifications I should be observing? Is this a known limitation of the Messages framework on iPad? Environment: Xcode 16 iOS 18 and 26 Testing on iPad Pro (M4) and iPad Air iPhone works correctly on all tested devices Any guidance would be greatly appreciated. This is blocking our App Store submission as reviewers are flagging the iPad behavior as incomplete functionality.
2
0
54
6d
Managing two helpbooks depending on MacOS user's version doesn't work
My application provides a unique feature for MacOS 26+ users, while keeping legacy for other versions (12.4+). So I aim to provide two help books localized package, depending on MacOS' version of the running computer. I designed two help bundles, with their own Info.plist files (identifiers, default filename…) and I've made multiple checks to verify that all their settings are correct and different when needed. As an app's info.plist can deal only with one Help Book, my application delegate registers both in applicationDidFinishLaunching: using: [[NSHelpManager sharedHelpManager] registerBooksInBundle:[NSBundle mainBundle]]; In Interface Builder, the help menu item is connected to the application delegate's "showHelp:" method to set the correct help package. The code in this method is: if (@available(macOS 26.0,*)){ helpbook = @"fr.myapp.updated.help"; } else { helpbook = @"fr.myapp.legacy.help"; } [[NSHelpManager sharedHelpManager] openHelpAnchor:@"index" inBook:helpbook]; The problem is that despite the MacOS version of the user's Mac, (either 15.1 or 26.2) , the «legacy» helpbook is always used. All default index.html (for each lproj) have a tag immediately after the I spent dozen of hours to understand the problem, forum parsing, including hours long dialogs with ChatGPT and Claude AIs (not mentioning MacOS' help system cache problems I could solve) I noticed also, to be complete, that when parsing the application package, opening the legacy .help with "Tips.app" always works, but with the "updated" one the help system opens with an "unavailable content" message. Both help bundles are fully included in the built application. Tested whether the app is installed in the debug directory, moved to in the Applications one, reboot, emptying/deleting cache files. So Houston, I have a problem… Any idea?
Topic: UI Frameworks SubTopic: AppKit
1
0
41
1w
When you set inputAccessoryView AND inputView you get unexpected system UI in between the two custom views
When you set inputAccessoryView AND inputView you get unexpected system UI in between the two custom views If anyone has a workaround for this I'd love to hear it. See also: https://stackoverflow.com/questions/79818015/uitextfield-custom-inputaccessoryview-with-custom-inputview-in-ios-26 Red == inputAccessoryView Blue == inputView Glassy bit in between == bug? // // ViewController.swift // Custom Keyboard // // Created by Lewis Smith on 19/02/2026. // import UIKit class ViewController: UIViewController { let textField = { let textField = UITextField() textField.translatesAutoresizingMaskIntoConstraints = false textField.backgroundColor = .yellow let inputAccessoryView = UIView(frame: CGRect(x: 0, y: 0, width: .zero, height: 70)) inputAccessoryView.backgroundColor = .red let inputView = UIView(frame: CGRect(x: 0, y: 0, width: .zero, height: 70)) inputView.backgroundColor = .blue // When you set inputAccessoryView AND inputView you get unexpected UI inbetweeen the two custom views textField.inputAccessoryView = inputAccessoryView textField.inputView = inputView textField.becomeFirstResponder() return textField }() override func viewDidLoad() { super.viewDidLoad() self.view.backgroundColor = .purple self.view.addSubview(textField) NSLayoutConstraint.activate([ textField.centerXAnchor.constraint(equalTo: view.centerXAnchor), textField.centerYAnchor.constraint(equalTo: view.centerYAnchor), textField.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 20), textField.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -20), ]) } }
Topic: UI Frameworks SubTopic: UIKit Tags:
2
0
69
1w
.navigationDestination(isPresented hangs after reboot in watchOS when destination view contains @Environment(\.dismiss)
.navigationDestination(isPresented) hangs after reboot (when called within 2 minutes of reboot) in watchOS when destination view contains @Environment(.dismiss). Feedback: FB21077151 Second button hangs after reboot. Hangs in watchOS 26.0 and 26.4 on a physical device. struct ContentView: View { @State var presentView1 : Bool = false @State var presentView2 : Bool = false var body: some View { NavigationStack { VStack { Button("Show View 1") { presentView1.toggle() } Button("Show View 2") { presentView2.toggle() } } .navigationDestination(isPresented: $presentView1, destination: {TestView1()}) .navigationDestination(isPresented: $presentView2, destination: {TestView2()}) } } } struct TestView1: View { var body: some View { Text("View 1") } } struct TestView2: View { @Environment(\.dismiss) var dismiss var body: some View { Text("View 2") } }
2
0
78
1w
WidgetKit: WidgetCenter.reloadAllTimelines() / reloadTimelines(ofKind:) requests are silently ignored/deferred, causing widget to remain unupdated UI Frameworks SwiftUI
Problem After launching the host app by tapping the widget (widgetURL), calls to: WidgetCenter.shared.reloadAllTimelines() WidgetCenter.shared.reloadTimelines(ofKind: ...) are ignored/deferred for an initial period right after the app opens. During this window, the widget does not reload its timeline and remains unupdated, no matter how many times I call the reload methods. After some time passes (typically ~30 seconds, sometimes shorter/longer), reload calls start working again. There is also no developer-visible signal (no callback/error/acknowledgement) that the reload was ignored, so the app can’t detect the failure and can’t reliably recover the flow. Question: Is this expected behavior (throttling/cooldown) after opening the app from a widget ? If so, is there any recommended workaround to update the widget reliably and quickly (or at least detect that the reload was not accepted)? Any guidance would help.
0
0
66
1w
sharedBackgroundVisibility Not Removing Spacing
Any logical reason why applying .sharedBackgroundVisibility(.hidden) to a ToolbarItem would not remove the spacing allocated for glass border? Thus causing any element utilizing this functionality to appear offset from the regular buttons. Or is this yet another magical Apple experience I am not blessed enough to understand.
4
0
114
1w
Sleep/Lock despite UIApplication.shared.isIdleTimerDisabled
I have an app that records video (and also provides a custom remote interface) so it needs to remain awake and in the foreground. It sets; UIApplication.shared.isIdleTimerDisabled = true I've also tried catching willEnterForegroundNotification to ensure it resets it if the app is backgrounded and resumes; .onReceive( NotificationCenter.default.publisher( for: UIApplication.willEnterForegroundNotification) ) { _ in UIApplication.shared.isIdleTimerDisabled = true } However, it seems that on some devices it will still go to sleep. This seems to be the case when Adaptive Power Mode is on (or rather, I've not managed to reproduce it when Adaptive Power Mode is off) even when battery percentage is well over 20% (I sort of expected Low Power Mode to trigger this) Am I missing something obvious? there must be a way to make sure media capture apps stay awake (I'm surprised AVFoundation doesn't do it anyway!) If it is related to Adaptive Power Mode, is there any way to detect that programatically to at least provide a warning to the user that having it on will affect operation of the app?
1
0
126
1w
UIHostingConfiguration focus problem on tvOS, with SwiftUI view
UIHostingConfiguration on tvOS: focus permanently broken with multiple focusable SwiftUI views Hi everyone, I'm working on a tvOS app with a UICollectionView. Some cells embed SwiftUI content via UIHostingConfiguration, specifically a row of 3 buttons that should be individually focusable. The cell itself returns canBecomeFocused = false so focus passes through to the SwiftUI buttons. The problem: after navigating focus into that section once, it becomes permanently unfocusable. Focus enters briefly, then immediately exits to nil on its own, without any user input. From that point on, the focus engine completely skips the section. The exact same SwiftUI view works perfectly when embedded via UIHostingController instead. How to reproduce Press DOWN to move focus into the UIHostingConfiguration section Focus lands on a SwiftUI button for a split second Focus exits on its own and bumps to another section The section is now dead, focus skips it on every subsequent navigation What the system logs say (-UIFocusLoggingEnabled YES) Right when focus enters, the system reports the SwiftUI focus items as "disappearing": Ignoring focus update request for disappearing focus environment <UIKitFocusSectionResponderItem> Then when searching for a new focusable item: <SwiftUI._UIInheritedView> → (warning) No focusable items found. <UIHostingContentView> → (warning) No focusable items found. === unable to find focused item in context. retrying with updated request. === The views are still in the hierarchy (verified by pointer), but the UIHostingContentView no longer exposes its virtual focus items. I also see mismatched parentFocusEnvironment on those items, pointing to a _UIHostingView from a completely different cell. What I've tried I've spent a lot of time on this with my colleagues, dug through the very limited documentation available online, and even used AI agents to help brainstorm. We tested 10 different approaches, none worked: Overriding preferredFocusEnvironments to point to the UIHostingContentView setNeedsFocusUpdate() / updateFocusIfNeeded(), rescan finds nothing Forcing UIKit redraws (setNeedsLayout, setNeedsDisplay) Removing .focusSection() Removing all SwiftUI animations, identical behavior Using canFocusItemAt: delegate instead of cell subclass, identical remembersLastFocusedIndexPath = true, causes a separate focus trap configurationUpdateHandler + setNeedsUpdateConfiguration(), config is rebuilt but virtual items stay deregistered Verified the UIHostingContentView never leaves the hierarchy. It doesn't, its internal state is just corrupted My workaround I switched to UIHostingController with proper view controller containment. It works because the hosting controller is a full UIFocusEnvironment, so the focus engine can traverse it and it correctly maintains its virtual items. Has anyone encountered this? Is there a known pattern for using UIHostingConfiguration on tvOS with multiple focusable SwiftUI elements? Or should I just file a Feedback? Thanks for any help!
1
0
55
1w
UIHostingConfiguration on tvOS, focus engine problem with SwiftUI and collectionView
UIHostingConfiguration on tvOS: focus permanently broken with multiple focusable SwiftUI views Hi everyone, I'm working on a tvOS app with a UICollectionView. Some cells embed SwiftUI content via UIHostingConfiguration, specifically a row of 3 buttons that should be individually focusable. The cell itself returns canBecomeFocused = false so focus passes through to the SwiftUI buttons. The problem: after navigating focus into that section once, it becomes permanently unfocusable. Focus enters briefly, then immediately exits to nil on its own, without any user input. From that point on, the focus engine completely skips the section. The exact same SwiftUI view works perfectly when embedded via UIHostingController instead. How to reproduce Press DOWN to move focus into the UIHostingConfiguration section Focus lands on a SwiftUI button for a split second Focus exits on its own and bumps to another section The section is now dead, focus skips it on every subsequent navigation What the system logs say (-UIFocusLoggingEnabled YES) Right when focus enters, the system reports the SwiftUI focus items as "disappearing": Ignoring focus update request for disappearing focus environment <UIKitFocusSectionResponderItem> Then when searching for a new focusable item: <SwiftUI._UIInheritedView> → (warning) No focusable items found. <UIHostingContentView> → (warning) No focusable items found. === unable to find focused item in context. retrying with updated request. === The views are still in the hierarchy (verified by pointer), but the UIHostingContentView no longer exposes its virtual focus items. I also see mismatched parentFocusEnvironment on those items, pointing to a _UIHostingView from a completely different cell. What I've tried I've spent a lot of time on this with my colleagues, dug through the very limited documentation available online, and even used AI agents to help brainstorm. We tested 10 different approaches, none worked: Overriding preferredFocusEnvironments to point to the UIHostingContentView setNeedsFocusUpdate() / updateFocusIfNeeded(), rescan finds nothing Forcing UIKit redraws (setNeedsLayout, setNeedsDisplay) Removing .focusSection() Removing all SwiftUI animations, identical behavior Using canFocusItemAt: delegate instead of cell subclass, identical remembersLastFocusedIndexPath = true, causes a separate focus trap configurationUpdateHandler + setNeedsUpdateConfiguration(), config is rebuilt but virtual items stay deregistered Verified the UIHostingContentView never leaves the hierarchy. It doesn't, its internal state is just corrupted My workaround I switched to UIHostingController with proper view controller containment. It works because the hosting controller is a full UIFocusEnvironment, so the focus engine can traverse it and it correctly maintains its virtual items. Has anyone encountered this? Is there a known pattern for using UIHostingConfiguration on tvOS with multiple focusable SwiftUI elements? Or should I just file a Feedback? Thanks for any help! You can find the code here : https://github.com/ThomasDutartre/focus-problem-tvos I recored the problem here : https://youtu.be/yPfM5AvU2ko
0
0
63
1w