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

The Nightmare of Small Toolbar Icons
When building in Xcode on MacOS Tahoe, it seems it is no longer possible to dynamically specify a "small" size toolbar for NSToolbar/NSToolbarItem. It works in MacOS code compiled and linked on earlier systems. I don't want to use "SFSymbol", or "templates". I have over 60 custom-made .png toolbars, in individual Image Set files, at the previous requisite sizes of 24x24 / 48x48, and 32x32 / 64x64. Sure -- I can configure an NSToolbar with whatever size .png assets I want. I just can't dynamically switch between the two groups of sizes. According to the Apple Coding Assistant, the only solution is to change the image names of each of the NSToolbarItems at runtime. OK -- but even when attempting that, the NSToolbarItems refuse to take on their smaller size... ...unless: they are attached to a custom view NSToolbarItem with an NSButton of style "Bevel". I have about 10 of those, and YES -- I CAN change those to a "small" size. Is this REALLY what I'm forced to do?! The Apple Coding Assistant just runs me around in circles, making coding suggestions that include properties that don't exists. I've gone around and around on these issues for over a week -- it can't be this hard, right? Is there no way to make multiple NSToolbar objects, one for "large" and one for "small"?
0
0
55
4d
How to align views in a LazyVGrid to a common base-line?
I have the following snippet (but you can see my entire code in GitHub, if you want): LazyVGrid(columns: columns) { ForEach(books) { book in BookView(book: book) .draggable(Book.BookTransferable(persistanceIdentifier: book.id)) } } and BookView is: VStack { Image(nsImage: book.image) .resizable() .frame(width: 150, height: 200) .scaledToFill() Text(book.title) .lineLimit(1) .font(.headline) HStack { ForEach(book.tags.sorted(), id: \.self) { tag in TagView(tag: tag, showText: false) } } } .padding() This will render each BookView on a different base-line because of the fact that the Text view sometimes takes 1, 2 or even 3 lines (as shown). How can I have all BookViews alligned at a common base-line (as it would if Text would only take one line, for example)?
0
0
32
4d
SwiftUI toolbar items clip DocumentGroup rename affordance
Hi — I’m seeing the DocumentGroup rename/title affordance get clipped on iPad when I populate the navigation bar with SwiftUI toolbar items in .topBarLeading, .principal, and .topBarTrailing (trailing is an HStack of controls). Example: .toolbar { ToolbarItem(placement: .topBarLeading) { UndoRedoControlsView(...) } ToolbarItem(placement: .principal) { Text(canvasInfoTitle).lineLimit(1) } ToolbarItem(placement: .topBarTrailing) { HStack { ... } } } .navigationBarTitleDisplayMode(.inline) Is there a recommended way to structure toolbar content so the system’s document title/rename control always has space (or a way to reserve space / avoid clipping), short of removing .principal or moving items into menus?
Topic: UI Frameworks SubTopic: SwiftUI
0
0
25
4d
Vision OS Persona
I’m seeing a camera/capture routing issue on visionOS when multiple WindowGroups are open at the same time. I have a SwiftUI view that starts an AVCaptureSession on onAppear and stops it on onDisappear. The camera feed is displayed in a subview that only exists inside one window. However, when I open additional windows (other WindowGroups) in the same app, the camera perspective/route changes unexpectedly — it looks like the capture is being re-associated with a different scene/window, even though the camera view never moved and no other view starts capture. Expected behavior Opening additional windows should not affect the active capture session or camera routing for the existing camera view. The camera feed should remain stable and tied to the window hosting. Actual behavior When multiple windows are open, the camera feed “switches perspective” / appears to re-route, as if the system changes which scene is considered active for capture. This happens without any explicit code calling startSession() again and without the camera view being present in the other windows. Additional context This app is running in an unbounded scene and uses Unity PolySpatial.
0
0
50
4d
Strong Password Suggestion Clears Other Secure Fields
I can't seem to find information on this but this is causing a critical bug where the Strong Password suggestion sheet presents on any secure field (UIKit) and clears the others when closing it. This means the user cannot enter a password when there is a secure confirm password field because switching fields clears the other. This looks to be a recent issue but I can't tell when this was introduced or if this is SDK / OS version related. I am finding it in both Xcode 26.2 and 16.4 when running on device (iOS 26.2.1 and XC 26 simulators). Code to reproduce: class ViewController: UIViewController { override func loadView() { let v = UIStackView() v.axis = .vertical v.layoutMargins = .init(top: 16, left: 16, bottom: 16, right: 16) v.isLayoutMarginsRelativeArrangement = true view = v let t1 = UITextField() t1.textContentType = .username t1.placeholder = "Username" v.addArrangedSubview(t1) let t2 = UITextField() t2.isSecureTextEntry = true t2.textContentType = .newPassword t2.placeholder = "Password" t2.clearsOnInsertion = false t2.clearsOnBeginEditing = false t2.passwordRules = nil t2.clearButtonMode = .always v.addArrangedSubview(t2) let t3 = UITextField() t3.isSecureTextEntry = true t3.textContentType = .newPassword t3.placeholder = "Confirm Password" t3.clearsOnInsertion = false t3.clearsOnBeginEditing = false t3.passwordRules = nil t3.clearButtonMode = .always v.addArrangedSubview(t3) v.addArrangedSubview(UIView()) } } No matter what textContentType is used the strong password still forcefully breaks the flow and blocks the user.
1
0
64
4d
NSTableView/NSScrollView jumping scroll position during NSSplitView resize
This is a very basic macOS Finder-style test app using AppKit. I am experiencing a "jump" in the vertical scroll position of my NSTableView (inside an NSScrollView) specifically when the window is resized horizontally. This happens when columns are visually added or removed. Framework: AppKit (Cocoa) Xcode/macOS: 26.2 Code: https://github.com/MorusPatre/Binder/blob/main/ContentView%20-%20Scroll%20Jump%20during%20Resize.swift
0
0
43
4d
UIScrollView Layout issue
I run into a layout problem where I cannot center an image inside ScrollView which is also inside Navigation Controller. The problem is surely the fact that there is a navigation bar because using this view without NavigationContoller works fine and the image is centered but I don’t know how to account for the space that navigation bar takes up. Here is the code: import UIKit class PhotoViewController: UIViewController { var photoName: String private lazy var photoView = { let image = UIImageView() image.translatesAutoresizingMaskIntoConstraints = false image.contentMode = .scaleAspectFit image.clipsToBounds = true return image }() var photoViewBottomConstraint: NSLayoutConstraint? var photoViewLeadingConstraint: NSLayoutConstraint? var photoViewTopConstraint: NSLayoutConstraint? var photoViewTrailingConstraint: NSLayoutConstraint? private lazy var scrollView = { let sv = UIScrollView() sv.translatesAutoresizingMaskIntoConstraints = false return sv }() override func viewDidLoad() { super.viewDidLoad() setupUI() } override func viewWillLayoutSubviews() { super.viewWillLayoutSubviews() updateMinZoomScaleForSize(view.bounds.size) } func updateMinZoomScaleForSize(_ size: CGSize) { let widthScale = size.width / photoView.bounds.width let heightScale = size.height / photoView.bounds.height let minScale = min(widthScale, heightScale) scrollView.minimumZoomScale = minScale scrollView.zoomScale = minScale } func setupUI() { photoView.image = UIImage(named: photoName) scrollView.delegate = self view.addSubview(scrollView) scrollView.addSubview(photoView) setupConstraints() } func setupConstraints() { NSLayoutConstraint.activate([ scrollView.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor), scrollView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor), scrollView.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor), scrollView.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor) ]) photoViewLeadingConstraint = NSLayoutConstraint( item: photoView, attribute: .leading, relatedBy: .equal, toItem: scrollView, attribute: .leading, multiplier: 1, constant: 0 ) photoViewTopConstraint = NSLayoutConstraint( item: photoView, attribute: .top, relatedBy: .equal, toItem: scrollView, attribute: .top, multiplier: 1, constant: 0 ) photoViewTrailingConstraint = NSLayoutConstraint( item: photoView, attribute: .trailing, relatedBy: .equal, toItem: scrollView, attribute: .trailing, multiplier: 1, constant: 0 ) photoViewBottomConstraint = NSLayoutConstraint( item: photoView, attribute: .bottom, relatedBy: .equal, toItem: scrollView, attribute: .bottom, multiplier: 1, constant: 0 ) photoViewLeadingConstraint?.isActive = true photoViewTopConstraint?.isActive = true photoViewTrailingConstraint?.isActive = true photoViewBottomConstraint?.isActive = true } init(photoName: String) { self.photoName = photoName super.init(nibName: nil, bundle: nil) } required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } } extension PhotoViewController: UIScrollViewDelegate { func viewForZooming(in scrollView: UIScrollView) -> UIView? { photoView } func scrollViewDidZoom(_ scrollView: UIScrollView) { updateConstraintsForSize(view.bounds.size) } func updateConstraintsForSize(_ size: CGSize) { let yOffset = max(0, (size.height - photoView.frame.height) / 2) photoViewTopConstraint?.constant = yOffset photoViewBottomConstraint?.constant = yOffset let xOffset = max(0, (size.width - photoView.frame.width) / 2) photoViewLeadingConstraint?.constant = xOffset photoViewTrailingConstraint?.constant = xOffset view.layoutIfNeeded() } }
1
0
86
4d
Crash/Exception thrown in UITableView initialization stack
Hello, We are seeing an intermittent crash when initializing a base UITableView with Apple's [initWithFrame:style:] initializer. Crash stack: Role: Foreground OS Version: iOS 26.1 Exception Type: EXC_BREAKPOINT Exception Subtype: KERN_INVALID_ADDRESS EXC_BREAKPOINT: 0 libswiftCore.dylib +0x1358c0 _assertionFailure(_:_:file:line:flags:) 1 UIKitCore +0x1fdca0 0x188c26ca0 (0x188c26b20 + 384) 2 UIKitCore +0x1ffa60 0x188c28a60 (0x188c2890c + 340) 3 UIKitCore +0x2012d0 0x188c2a2d0 (0x188c2a1ec + 228) 4 UIKitCore +0x200f20 0x188c29f20 (0x188c29cac + 628) 5 UIKitCore +0x200428 0x188c29428 (0x188c29384 + 164) 6 UIKitCore +0x18af7f4 -[UITableMetricsAdapter _updateSharedSectionMetricsForListGeometry:] 7 UIKitCore +0x201da8 -[UITableMetricsAdapter tableBackgroundColor] 8 UIKitCore +0x1643a44 ___39-[UITableView _applyAppearanceDefaults]_block_invoke 9 UIKitCore +0x196f3d0 +[UIView _performSystemAppearanceModifications:] 10 UIKitCore +0x1643978 -[UITableView _applyAppearanceDefaults] 11 UIKitCore +0x202854 -[UITableView _setupTableViewCommon] 12 UIKitCore +0x1643760 -[UITableView initWithFrame:style:] 13 Application +0x30b6a40 closure #1 in variable initialization expression of MyAppClass.tableView 14 Application +0x30b6ef0 MyAppClass.init(frame:) Has anyone else seen something like this? Any insights or advice is much appreciated, thank you!
1
0
72
5d
Severe Frame Drops When Resizing macOS Window with Dynamic LazyVGrid
Context: I am building a macOS file (currently image only) browser using SwiftUI. The core view is a ScrollView containing a LazyVGrid. The layout is dynamic: as the window resizes, I calculate the optimal number of columns and spacing using a GeometryReader. The Issue: While scrolling is pretty smooth (thanks to custom image caching and prefetching), window resizing is significantly laggy. After having scrolled the UI stutters and drops frames heavily while dragging the window edge. The Code: https://github.com/MorusPatre/Binder
1
0
68
5d
.glassProminent leading toolbar item animation issue on push navigation
Hi, I have an issue with applying the .glassProminent modifier to a button placed in the leading section the nav bar that triggers a push navigation to another screen in iOS 26. I have made a simple sample project to verify it happens there too, and I'm getting the same behaviour where the prominent button "flashes" with a darker background and disappears. The HIG does mention not tinting or adding custom backgrounds to tool bar items in iOS 26, so I'm unsure if this is a bug in iOS 26 or the unexpected behaviour they refer to when adding custom tint/backgrounds. Below is the simplified sample app code: var body: some View { NavigationStack { VStack { Text("Main Screen") .font(.largeTitle) } .navigationTitle("Home") .navigationBarTitleDisplayMode(.inline) .toolbar { ToolbarItem(placement: .navigationBarLeading) { NavigationLink(destination: SecondScreen()) { Text("Push Nav") } .buttonStyle(.glassProminent) } } } } } struct SecondScreen: View { var body: some View { VStack { Text("Second Screen") .font(.largeTitle) } .navigationTitle("Settings") .navigationBarTitleDisplayMode(.inline) } }
Topic: UI Frameworks SubTopic: SwiftUI
2
0
106
5d
Image not rendering on some devices
Hi, new developer here. I have an issue where an image I have on app is not showing up on some devices. The image is: Resources/Assets/logo: I am using it in my app like: ZStack { Color.white .ignoresSafeArea() VStack { Spacer() Image("logo") Spacer() Text(dateString) .font(.custom("LinLibertine", size: 17)) .fontWeight(.bold) .tracking(5) .padding(.bottom, 50) } } The image appears fine on all simulators. And also on my real device iPad with A14. But when I run it on iPhone 8 or iPad Air M4, it shows empty space in place of image. I tried many different options like: Image("logo") .renderingMode(.original) .resizable() .scaledToFit() frame(width: 300) .background(Color.red.opacity(0.3)) But nothing works. What can be the issue?
2
1
114
6d
How to avoid this thread priority inversions ?
Context: Xcode 16.4, Appkit In a windowController, I need to create and send a mouseDown event (newMouseDownEvent). I create the event with: let newMouseDownEvent = NSEvent.mouseEvent( with: .leftMouseDown, location: clickPoint, // all other fields I also need to make window key and front, otherwise the event is not handled.   func simulateMouseDown() { self.window?.makeFirstResponder(self.window) self.calepinFullView.perform(#selector(NSResponder.self.mouseDown(with:)), with: newMouseDownEvent!) }   As I have to delay the call( 0.5 s), I use asyncAfter: DispatchQueue.main.asyncAfter(deadline: .now() + 0.5, qos: .userInteractive) { self.simulateMouseDown() }   It works as intended, but that generates the following (purple) warning at runtime: [Internal] Thread running at User-interactive quality-of-service class waiting on a lower QoS thread running at Default quality-of-service class. Investigate ways to avoid priority inversions I have tried several solutions, change qos in await: DispatchQueue.main.asyncAfter(deadline: .now() + 0.5, qos: ..default) call from a DispatchQueue let interactiveQueue = DispatchQueue.global(qos: .userInteractive) interactiveQueue.async { self.window?.makeFirstResponder(self.window) self.calepinFullView.perform(#selector(NSResponder.self.mouseDown(with:)), with: newMouseDownEvent!) } But that's worse, it crashes with the following error: FAULT: NSInternalInconsistencyException: -[HIRunLoopSemaphore wait:] has been invoked on a secondary thread; the problem is likely in a much shallower frame in the backtrace; { NSAssertFile = "HIRunLoop.mm"; NSAssertLine = 709; }   How to eliminate the priority inversion risk (not just silencing the warning) ?
0
0
72
6d
WidgetKit (systemMedium) SwiftUI Text: auto-fit to the largest font size without “…”
Hi all, I’m stuck on a WidgetKit/SwiftUI layout issue. I have a systemMedium widget that shows a block of text. What I want is simple: The text should be as large as possible But it must always fully fit inside the widget No ellipsis (“…”) Short text → big font Longer text → shrink only as much as needed The problem: when I try to make the font larger, the widget often shows only a couple of words and then “…” (or it looks like it’s truncating/clipping), even though I’m using multiline text (lineLimit(nil) etc.). If I keep a small fixed font size, the entire text shows fine — so the input string isn’t truncated. I tried a few approaches: ViewThatFits seeing which font size fits minimumScaleFactor Measuring with NSAttributedString.boundingRect + binary search to calculate the biggest font size that should fit But WidgetKit still behaves inconsistently and I can’t get a reliable “largest size that fits” result. Is there a recommended, production-safe way to do this in WidgetKit? Also: can a SwiftUI Text still end up showing “…” in a widget even with .lineLimit(nil) when it’s constrained vertically? Thanks in advance — any pointers or known patterns would really help.
0
0
48
6d
SwiftUI mysterious behavior
Hello dear developers! Recently, I stumbled upon some really strange behavior of SwiftUI and I’m very curious why it works this way struct ContentView: View { @State private var title: String? @State private var isSheetPresented: Bool = false var body: some View { Button("Hello, world!") { title = "Sheet title" isSheetPresented = true } .sheet(isPresented: $isSheetPresented, content: { if let title { Text(title) } else { EmptyView() } }) } } Why in this case when we tap the button and sheet comes in we go to the branch else even though we set title before isSheetPresented but it still somehow nil But what really drive me crazy is that if we change a little bit code to this: I just added another @State property 'number' and use it as the Button's title. In this scenario it works 😃 and Text in the sheet view appearing struct ContentView: View { @State private var title: String? @State private var number = 0 @State private var isSheetPresented = false var body: some View { Button("\(number)") { title = "Sheet title" number += 0 isSheetPresented = true } .sheet(isPresented: $isSheetPresented, content: { if let title { Text(title) } else { EmptyView() } }) } } Is this somehow related to what happens under the hood like View Tree and Render Tree (Attribute Graph)? Maybe because ContentView’s body doesn't capture title it cannot be stored in the Render Tree so it always would have the initial value of nil? if there are any well-informed folks here, please help me figure out this mystery, I’d appreciate it!!! p.s. Don’t get me wrong. Im not interested in how to make it work. I’m interested in why this doesn’t work and what really happens under the hood that led to this result
2
0
103
1w
Whimsical tooltips behaviour in popover (Appkit)
In this app I use tooltips extensively. They work perfectly well, except in a popover where they may appear or not (just some flash and immediately disappear). In the popover there are 12 colour buttons, each with its own tracking area and 3 control buttons, with their tracking areas. Here when it works, hovering over "C" button or "Annuler" button: But then, when I move to another colour button, a few 2 or 3 may work, but most don't display their tooltip at all. I know that the tooltip is set because I replicate the message in a help line at the bottom of the screen and this line always update: Let messageForColor = "Choisir la couleur…" if button.isEnabled { // show tooltip button.toolTip = messageForColor } else { button.toolTip = nil } if button.isEnabled { // Shows helpline at the bottom of screen button.helpMessage = messageForColor } Maybe it comes from some useDefault (I modified NSInitialTool TipDelay and I'm not sure I have reset to the default value) I noted that if I wait for 10 seconds or so (keeping the popover opened), everything seems to work properly again. Just as if there was some lengthy initialisation going on. So questions: Is there a known issue of Tooltips in a popover ? Are there other parameters to set in userDefaults to avoid immediate disparition of the tooltip in popover ? How to reset the factory setting for the UserDefaults in the app ?
5
0
357
1w
SwiftUI List: observable reference types not deallocated immediately after refresh
Hello 👋 I ran into a SwiftUI lifecycle gotcha while debugging a List with .refreshable I share the code used to reproduce the issue @Observable final class CounterModel: Identifiable { let id: String var title: String var value: Int init(id: String, title: String, value: Int = 0) { self.id = id self.title = title self.value = value } deinit { print("deinit", title) } } @Observable final class ObservableCountersStore { var counters: [CounterModel] = [ .init(id: "1", title: "A"), .init(id: "2", title: "B"), .init(id: "3", title: "C") ] func refresh() async { try? await Task.sleep(nanoseconds: 300_000_000) counters = [.init(id: "4", title: "D")] } } struct ObservableCountersListView: View { @State private var store = ObservableCountersStore() var body: some View { List { ForEach(store.counters) { counter in ObservableCounterRow(counter: counter) } } .refreshable { await store.refresh() } } } struct ObservableCounterRow: View { let counter: CounterModel var body: some View { Text(counter.title) } } Observation: After calling refresh(), only some of the previous CounterModel only one CounterModel is deallocated immediately. Others are retained This doesn’t look like a leak, but it made me realize that passing observable reference types directly into List rows leads to non-deterministic object lifetimes, especially with .refreshable. Posting this as a gotcha — curious if this matches intended behavior or if others have run into the same thing.
2
0
156
1w
iOS 26.0+: sceneDidBecomeActive / applicationDidBecomeActive fires during Lock button press while app is active
Hi all, I’m seeing a lifecycle behavior change on iOS 26.0 (and up). While my app is in the foreground and active, pressing the hardware Lock button triggers didBecomeActive callbacks/notifications even though the app is transitioning away from active state. I’m observing this sequence: willResignActive didBecomeActive willResignActive didEnterBackground This happens for: • UISceneDelegate.sceneDidBecomeActive(:) • UIApplicationDelegate.applicationDidBecomeActive(:) • UIApplication.didBecomeActiveNotification On iOS 18 (same app, same code) I do not see didBecomeActive in the middle of locking/backgrounding. Problem is reproduced on totally new project. I would expect a normal transition to background: • willResignActive → didEnterBackground …and no extra didBecomeActive between them. I have “became active” logic (refresh UI/state, resume timers, analytics). On iOS 26.0 this logic runs unexpectedly during locking, causing unnecessary work and incorrect state transitions. Is this callback ordering expected on iOS 26.0 when pressing the Lock button? If expected, what’s the recommended way to detect a “real” activation (and avoid transient didBecomeActive during locking/backgrounding)? If this is a regression, is there a known workaround or best practice?
Topic: UI Frameworks SubTopic: UIKit Tags:
1
2
119
1w
macOS 26.3 RC breaks all borderless window interactions
After updating to macOS 26.3 Release Candidate, all interactions for borderless windows are no longer working. In macOS 26.3 Beta, borderless windows behaved correctly: • Mouse clicks were received normally • Window dragging worked as expected • Interaction logic was fully functional However, in macOS 26.3 RC, all of the above behaviors are broken: • Click events are not delivered • Windows cannot be moved or interacted with • The issue affects all borderless windows This is a regression from the Beta build and appears to be system-level, not app-specific. Environment: • macOS: 26.3 RC • Window type: borderless / frameless windows • Status in 26.3 Beta: working correctly • Status in 26.3 RC: completely broken Could Apple confirm whether this is a known issue or an intentional behavior change in 26.3 RC? If this is a , is there a recommended workaround before the final release? Thanks.
Topic: UI Frameworks SubTopic: AppKit
2
0
137
1w
Can I disable a SwiftUI View from being a draggable source, but still leave it enabled as a dropDestination?
My app has a collection of Cell Views. some of the views' model objects include a Player, and others do not. I want to use drag and drop to move a player from one cell to another. I only want cells that contain a player to be valid drag sources. All cells will be valid drop destinations. When I uncomment the .disabled line both drag and drop become disabled. Is it possible to keep a view enabled as a dropDestination but disabled as a draggable source? VStack { Image("playerJersey_red") if let player = content.player { Text(player.name) } } .draggable(content) // .disabled(content.player == nil) .dropDestination(for: CellContent.self) { items, location in One thing I tried was to wrap everything in a ZStack and put a rectangle with .opacity(0.02) above the Image/Text VStack. I then left draggable modifying my VStack and moved dropDestination to the clear rectangle. This didn't work as I wasn't able to initiate a drag when tapping on the rectangle. Any other ideas or suggestions? thanks
4
0
172
1w