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

Can't find any realistic example of how to use NavigationPath
Like many applications, mine involves navigation where the user starts a process on one screen and then progresses through several more steps to reach a conclusion. When he confirms that choice, I need to dismiss the entire stack. In my case, he's browsing contacts, selecting one, and then selecting a communication method from those offered by the contact. This still appears to be a PITA in SwiftUI. NavigationPath is supposed to provide a way to programmatically control a stack of views. Well... I can't find a single example of how to use it for this, except with absurdly shallow (as in a single level) of child views that all take the same datatype. Nowhere do I see how to use the path as users proceed through your view hierarchy with NavigationLinks. I have not seen any example of how elements get added to the path or how they are related to each added view. Nor can I find an example of popping views off the stack by removing related elements from the path. I created a class that encloses a NavigationPath: @Observable class NavPathController { var path: NavigationPath init() { path = NavigationPath() } func popOne() { path.removeLast() } func popAll() { path.removeLast(path.count) } } In my root view, I pass a binding to this controller's NavigationPath when creating the NavigationStack: @State private var viewStack = NavPathController() var body: some View { NavigationStack(path: $viewStack.path) { VStack() { NavigationLink(destination: UserFindingView(viewPathController: viewStack), label: { Text("Pick a recipient") }) } } And likewise each view passes the same view-path controller object to each child view that's invoked with a NavigationLink (instead of using an environment variable, because I find those hokey). But in the end, the path is empty; not surprisingly, clearing it does not pop the views. So how is one supposed to make this work?
Topic: UI Frameworks SubTopic: SwiftUI
1
0
210
Mar ’25
What happened to readable margins?
Am in the process of migrating some UIKit based apps over to SwiftUI, but for the life of me I cannot find the SwiftUI equivalent of Readable Content Margins. I have come across some workarounds that kind of, sort of work, but do not produce the same results when compared to running the same user interface written using UIKit on several sizes of iPads in portrait and landscape orientiations. is it something Apple has not gotten around to yet, because I realize SwiftUI is a work-in-progress, or do we not care about creating consistent readable margins in our apps anymore?
2
0
336
Mar ’25
drag a modelEntity inside an Immersive space and track position
Goal : Drag a sphere across the room and track it's position Problem: The gesture seems to have no effect on the sphere ModelEntity. I don't know how to properly attach the gesture to the ModelEntity. Any help is great. Thank you import SwiftUI import RealityKit import RealityKitContent import Foundation @main struct testApp: App { @State var immersionStyle:ImmersionStyle = .mixed var body: some Scene { ImmersiveSpace { ContentView() } .immersionStyle(selection: $immersionStyle, in: .mixed, .full, .progressive) } } struct ContentView: View { @State private var lastPosition: SIMD3<Float>? = nil @State var subscription: EventSubscription? @State private var isDragging: Bool = false var sphere: ModelEntity { let mesh = MeshResource.generateSphere(radius: 0.05) let material = SimpleMaterial(color: .blue, isMetallic: false) let entity = ModelEntity(mesh: mesh, materials: [material]) entity.generateCollisionShapes(recursive: true) return entity } var drag: some Gesture { DragGesture() .targetedToEntity(sphere) .onChanged { _ in self.isDragging = true } .onEnded { _ in self.isDragging = false } } var body: some View { Text("Hello, World!") RealityView { content in //1. Anchor Entity let anchor = AnchorEntity(world: SIMD3<Float>(0, 0, -1)) let ball = sphere //1.2 add component to ball ball.components.set(InputTargetComponent()) //2. add anchor to sphere anchor.addChild(ball) content.add(anchor) subscription = content.subscribe(to: SceneEvents.Update.self) { event in let currentPosition = ball.position(relativeTo: nil) if let last = lastPosition, last != currentPosition { print("Sphere moved from \(last) to \(currentPosition)") } lastPosition = currentPosition } } .gesture(drag) } }
0
0
68
Apr ’25
SwiftUI macOS simple NavigationStack and NavigationLink -> problem on multiplatform project
I had a problem with my app (or in my setup) and searching the web I found a very simple code where part of my problem occurs. I create a new Multiplatform App and paste this code in ContentView. import SwiftUI struct ContentView: View { var body: some View { NavigationStack { VStack { Text("Navigation article") .font(.title) .padding() NavigationLink("Go to the second view", destination: SecondView()) .padding() } .navigationTitle("First View") } } } struct SecondView: View { var body: some View { Text("This is the Second view") .font(.headline) .padding() .navigationTitle("Second View") } } run on iPhone/ iOS no problem run on a Mac/macOS Going from view 1 to view 2 work, the back arrow on view 2 is there, and it is working but the second time I go to the view 2, the back arrow is gone. after looking closely I can see the Arrow Underneath the S of SecondView. I have tried many things and could not make it work. I post this in a HackingWithSwift forum and somebody tried the code and said it work. so it seems the problem could be related to my setup but I create another user in my computer , same problem and tried it on my another computer, same problem.
Topic: UI Frameworks SubTopic: SwiftUI
7
0
93
Apr ’25
Disable collapsing Sidebar/NavigationSplitView
I want to keep the sidebar fixed in NavigationSplitView. I don’t want the user to be able to open or close the sidebar. I removed the toggle button, but I still couldn’t make the sidebar stay fixed. It can still be closed using Cmd + Alt + S or by dragging. What I want is just to disable the resize feature of the sidebar. Isn’t it possible with SwiftUI? NavigationSplitView is kind of blackhole :) LeftSidebarView() .environmentObject(detailView) .toolbar(removing: .sidebarToggle) .navigationSplitViewColumnWidth(240)
1
0
223
Mar ’25
What is com.apple.TextInput.rdt?
Hello, community, I'm using an HTML editor in a .NET MAUI application running on macOS, and I'm encountering some unexpected behavior during text editing: Double-click text selection disappears after approximately one second. Styles randomly revert or are applied to the wrong text unexpectedly. It appears to be related to macOS spell checking. When using editable elements (, or with contenteditable), the system enables spell checking by default. During this, MAUI attempts to communicate with a system process: com.apple.TextInput.rdt, which is not running, leading to repeated errors like: Error Domain=NSCocoaErrorDomain Code=4099 "The connection to service named com.apple.TextInput.rdt was invalidated: failed at lookup with error 3 - No such process." Question: What is com.apple.TextInput.rdt, and why might it not be running? Thank you for any help!
2
0
177
Mar ’25
Crash on removal of QLPreviewController and _EXRemoteViewController
I have a controller that displays a pdf using UIDocumentInteractionController as the presented view. When users open it up, it shows fine. User gets the app backgrounded and session timed out. After timed out, when the app is brought to foreground, I bring our loginVC by removing the old VC used to show the UIDocumentInteractionController. All the crashes are happening at this point. I am not able to reproduce it, but our alert systems show we have crashes happening. The code that shows the pdf is straight forward documentViewController = UIDocumentInteractionController() documentViewController?.delegate = self documentViewController?.url = url documentViewController?.presentPreview(animated: true) and we reset it to nil in delegate documentInteractionControllerDidEndPreview Based on the crash trace, it seems like the crash happens when our login VC replaces it and only when pdf was displayed. The reason of stressing ONLY because when we have other viewcontroller present and they are removed in a similar way, we do not see any issue. So we always replace first and then add a new one childViewController.willMove(toParent: nil) childViewController.viewIfLoaded?.removeFromSuperview() childViewController.removeFromParent() addChild(childViewController) view.addSubview(childViewController.view) childViewController.view.frame = view.bounds childViewController.didMove(toParent: self) Raised a ticket with Apple, but I haven't heard back, and it's been a month. Posting here in case anyone experiences the same and has any solutions. I saw some related posts, and solution was to remove the pdf the moment the app goes to the background, but I am trying to find some alternate solution if possible.
Topic: UI Frameworks SubTopic: UIKit
0
0
224
Mar ’25
How to customize item transitions inside a Picker View?
I have a simple Picker where the options available change by the view state. I would like to have the transition animated but the default animation is not good so I tried setting a .transition() and or an .animation() inside an item on the picker but it is ignored. The same happens if the transition is set on the picker itself since it's always present. Am I doing it right and is just not posible or is there something else to do? Code to reproduce the issue: struct ContentView: View { @State var list: [String] = [ "Item 4", "Item 5", "Item 6", "Item 7", "Item 8", ] @State var selected: String? @State var toggle: Bool = false var body: some View { VStack { Picker("List", selection: $selected) { ForEach(list, id: \.self) { Text($0).tag($0) // .transition(.opacity) } } .pickerStyle(.segmented) // .transition(.opacity) HStack { Button(action: swapOptions) { Text("Swap") } } } .padding() } } extension ContentView { func swapOptions() { withAnimation { toggle.toggle() switch toggle { case true: list = [ "Item 1", "Item 2", "Item 3", "Item 4", "Item 5", ] case false: list = [ "Item 4", "Item 5", "Item 6", "Item 7", "Item 8", ] } } } } ``
Topic: UI Frameworks SubTopic: SwiftUI
0
0
96
May ’25
NSView.knowsPageRange(_:) called twice when showing print panel
When creating a default macOS document-based Xcode project and using the code below (and wiring the File menu's Print item to printDocument: instead of the default print:, which does nothing), opening the print panel causes PrintView.knowsPageRange(_:) to be called twice. Is this a bug? My app populates PrintView dynamically, and for large documents it can be quite inefficient to populate it once, only for the contents to be immediately discarded and populated again. A workaround that came to my mind would be to check if the print options have changed, though I'm not sure if it's a reliable indicator that the print preview is effectively the same. I created FB17018494. class Document: NSDocument { override func makeWindowControllers() { addWindowController(NSStoryboard(name: NSStoryboard.Name("Main"), bundle: nil).instantiateController(withIdentifier: NSStoryboard.SceneIdentifier("Document Window Controller")) as! NSWindowController) } override func printOperation(withSettings printSettings: [NSPrintInfo.AttributeKey : Any]) throws -> NSPrintOperation { return NSPrintOperation(view: PrintView(frame: CGRect(x: 0, y: 0, width: 100, height: 100)), printInfo: NSPrintInfo(dictionary: printSettings)) } } class PrintView: NSView { override func knowsPageRange(_ range: NSRangePointer) -> Bool { print("knowsPageRange") range.pointee = NSRange(location: 1, length: 1) return true } }
Topic: UI Frameworks SubTopic: AppKit
1
0
77
Mar ’25
business
import SwiftUI struct Product: Identifiable { let id = UUID() let name: String let pricePerKg: Double } struct ContentView: View { @State private var selectedProduct: Product? @State private var quantity: Double = 1.0 @State private var orderDate = Date() @State private var showingConfirmation = false let products = [ Product(name: "Lamb", pricePerKg: 15.0), Product(name: "Beef", pricePerKg: 20.0), Product(name: "Chicken", pricePerKg: 10.0) ] var body: some View { NavigationView { Form { Section(header: Text("Select Meat")) { Picker("Meat Type", selection: $selectedProduct) { ForEach(products) { product in Text(product.name).tag(product as Product?) } } } if let selectedProduct = selectedProduct { Section(header: Text("Quantity (kg)")) { Stepper(value: $quantity, in: 0.5...10, step: 0.5) { Text("\(quantity, specifier: "%.1f") kg") } } Section(header: Text("Delivery Date")) { DatePicker("Select Date", selection: $orderDate, in: Date()..., displayedComponents: .date) } Section(header: Text("Total Price")) { Text("$\(selectedProduct.pricePerKg * quantity, specifier: "%.2f")") } Button("Confirm Order") { showingConfirmation = true } .alert(isPresented: $showingConfirmation) { Alert(title: Text("Order Confirmed"), message: Text("You have ordered \(quantity, specifier: "%.1f") kg of \(selectedProduct.name) for \(orderDate.formatted(date: .long, time: .omitted))."), dismissButton: .default(Text("OK"))) } } } .navigationTitle("Halal Butcher") } } } @main struct HalalButcherApp: App { var body: some Scene { WindowGroup { ContentView() } } }
2
0
219
Mar ’25
Picker with inline style on tvOS 18
Since tvOS 18, my Picker view with inline style is not showing the checkmark on the selected item. enum Flavor: String, Identifiable { case chocolate, vanilla, strawberry var id: Self { self } } struct ContentView: View { @State private var selectedFlavor: Flavor = .chocolate var body: some View { NavigationView { Form { Picker("Flavor", selection: $selectedFlavor) { Text("Chocolate").tag(Flavor.chocolate) Text("Vanilla").tag(Flavor.vanilla) Text("Strawberry").tag(Flavor.strawberry) }.pickerStyle(.inline) } } } } Am I missing something? When I run this on tvOS 17.x, it works fine.
2
0
100
Mar ’25
Serious Bug with SwiftUI/ImagePicker/Camera + workaround
I was doing an app which had several "camera" buttons each one dedicated to taking/storing/reviewing/deleting an image associated with a variable URL but what should have been a simple no brainer turned out to be a programming nightmare. To cut a long story short there is a bug in the sheet handling wherebye even tho you have separate instance for each button the camera/picker cylcles sequentially thru the stack of instances for any action finally always placing the image in the first URL. Working with myself debugging, all major AIs (Grok, Claude, Gemini and Perplexity) after 4 x 12hr+ days we finally managed to crack a solution. What follows is Groks interpretation (note it misses the earlier problem of instance cycling!!) ... You can follow the discussion here: https://x.com/i/grok/share/KHeaUPladURmbFq5qy9W506er but be warned its long a detailed but if you are having problems then read ... **Bug Report: Race Conditions with UIImagePickerController in SwiftUI Sheet ** Environment: SwiftUI, iOS 17.7.5 Device: iPad Pro (12.9-inch, 2nd generation) Xcode Version: [Insert your Xcode version] Date: March 30, 2025 **Issue 1: Multiple Instances of UIImagePickerController Spawned After Dismissal ** Description: When using a UIImagePickerController wrapped in a UIViewControllerRepresentable and presented via a SwiftUI .sheet, selecting "Use Photo" resulted in multiple unintended instances of the picker being initialized and presented. The console logs showed repeated "Camera initialized" and "Camera sheet appeared" messages (e.g., multiple <UIImagePickerController: 0x...> instances) after the initial dismissal, despite the sheet being dismissed programmatically. Reproduction Steps: Create a SwiftUI view with a button that sets a @State variable showCamera to true. Present a UIImagePickerController via .sheet(isPresented: $showCamera). Update a @Binding variable (e.g., photoLocation: URL?) in imagePickerController(_:didFinishPickingMediaWithInfo:) after saving the image. Dismiss the picker with picker.dismiss(animated: true) and presentationMode.wrappedValue.dismiss(). Observe that updating the @Binding variable triggers a view re-render, causing the .sheet to re-present multiple times before finally staying dismissed. Root Cause: A race condition occurred between the view update (triggered by changing photoLocation) and the dismissal of the picker. During the re-render, showCamera remained true momentarily, causing the .sheet modifier to re-evaluate and spawn new picker instances before the onDismiss closure could reset showCamera to false. The fix involved delaying the @Binding update (photoLocation) until after the picker and sheet were fully dismissed, ensuring showCamera was reset to false before the view re-rendered: Introduced an onPhotoPicked: (URL) -> Void closure to decouple the photoLocation update from the dismissal timing. Modified the coordinator to call onPhotoPicked and reset showCamera before initiating dismissal:swift Issue 2: Single Unintended Picker Reopen After Initial Fix Description: After addressing the multiple-instance issue, a single unintended reopen of the picker persisted. The logs showed one additional "Camera initialized" and "Camera sheet appeared" after "Use Photo," before the final dismissal. Reproduction Steps: Reproduction Steps: Use the initial fix with onPhotoPicked and delayed photoLocation update. Take a photo and select "Use Photo." Observe one extra picker instance appearing briefly before dismissal completes. Root Cause: The @Binding update (photoLocation) was still occurring too early in the dismissal sequence. Although delayed until after picker.dismiss, the view re-render happened while showCamera was still true during the dismissal animation, causing the .sheet to re-present once before onDismiss reset showCamera. Resolution: The fix ensured showCamera was set to false before the picker dismissal animation began, preventing the .sheet from re-evaluating during the transition: Moved the dismissCamera() call (which sets showCamera to false) into the onPhotoPicked callback, executed before picker.dismiss: CameraView( photoLocation: $photoLocation, storeDirectory: storeDirectory, onPhotoPicked: { url in print("Photo picked callback for \(id), setting photoLocation: \(url)") self.photoLocation = url self.cameraState.dismissCamera() // Sets showCamera to false first } ) Kept the dismissal sequence in the coordinator: DispatchQueue.main.async { self.parent.onPhotoPicked(fileURL) picker.dismiss(animated: true) { self.parent.presentationMode.wrappedValue.dismiss() } } This synchronized the state change with the dismissal, ensuring showCamera was false before the view re-rendered, eliminating the single reopen. Request: Could the SwiftUI team clarify if this behavior is expected, or consider improving the .sheet modifier to better handle state transitions during UIKit controller dismissal? A more robust bridge between SwiftUI’s declarative state and UIKit’s imperative lifecycle could prevent such race conditions.
Topic: UI Frameworks SubTopic: UIKit Tags:
1
0
94
Mar ’25
Data Fetch issue from SensorKit
I want use SensorKit data for research purposes in my current app. I have applied for and received permission from Apple to access SensorKit Data. I have granting all the necessary permissions. But no data retrieved. I am using didCompleteFetch for retrieving data from Sensorkit. CompleteFetch method calls but find the data. Below is my SensorKitManager Code. import SensorKit import Foundation protocol SensorManagerDelegate: AnyObject { func didFetchPhoneUsageReport(_ reports: [SRPhoneUsageReport]) func didFetchAmbientLightSensorData(_ data: [SRAmbientLightSample]) func didFailFetchingData(error: Error) } class SensorManager: NSObject, SRSensorReaderDelegate { private let phoneUsageReader: SRSensorReader private let ambientLightReader: SRSensorReader weak var delegate: SensorManagerDelegate? override init() { self.phoneUsageReader = SRSensorReader(sensor: .phoneUsageReport) self.ambientLightReader = SRSensorReader(sensor: .ambientLightSensor) super.init() self.phoneUsageReader.delegate = self self.ambientLightReader.delegate = self } func requestAuthorization() { let sensors: Set<SRSensor> = [.phoneUsageReport, .ambientLightSensor] guard phoneUsageReader.authorizationStatus != .authorized || ambientLightReader.authorizationStatus != .authorized else { log("Already authorized. Fetching data directly...") fetchSensorData() return } SRSensorReader.requestAuthorization(sensors: sensors) { [weak self] error in DispatchQueue.main.async { if let error = error { self?.log("Authorization failed: \(error.localizedDescription)", isError: true) self?.delegate?.didFailFetchingData(error: error) } else { self?.log("Authorization granted.") self?.fetchSensorData() } } } } func fetchSensorData() { guard let fromDate = Calendar.current.date(byAdding: .day, value: -1, to: Date()) else { log("Failed to calculate 'from' date.", isError: true) return } let fromTime = SRAbsoluteTime.fromCFAbsoluteTime(_cf: fromDate.timeIntervalSinceReferenceDate) let toTime = SRAbsoluteTime.fromCFAbsoluteTime(_cf: Date().timeIntervalSinceReferenceDate) let phoneUsageRequest = SRFetchRequest() phoneUsageRequest.from = fromTime phoneUsageRequest.to = toTime phoneUsageRequest.device = SRDevice.current let ambientLightRequest = SRFetchRequest() ambientLightRequest.from = fromTime ambientLightRequest.to = toTime ambientLightRequest.device = SRDevice.current phoneUsageReader.fetch(phoneUsageRequest) ambientLightReader.fetch(ambientLightRequest) } // ✅ Delegate Methods func sensorReader(_ reader: SRSensorReader, didCompleteFetch fetchRequest: SRFetchRequest) { Task.detached { if reader.sensor == .phoneUsageReport { if let samples = reader.fetch(fetchRequest) as? [SRPhoneUsageReport] { DispatchQueue.main.async { [weak self] in self?.delegate?.didFetchPhoneUsageReport(samples) } } } else if reader.sensor == .ambientLightSensor { if let samples = reader.fetch(fetchRequest) as? [SRAmbientLightSample] { DispatchQueue.main.async { [weak self] in self?.delegate?.didFetchAmbientLightSensorData(samples) } } } } } func sensorReader(_ reader: SRSensorReader, fetching fetchRequest: SRFetchRequest, didFetchResult result: SRFetchResult<AnyObject>) -> Bool { return true } func sensorReader(_ reader: SRSensorReader, fetching fetchRequest: SRFetchRequest, failedWithError error: any Error) { DispatchQueue.main.async { [weak self] in self?.delegate?.didFailFetchingData(error: error) } } // MARK: - Logging Helper private func log(_ message: String, isError: Bool = false) { if isError { print("❌ [SensorManager] \(message)") } else { print("✅ [SensorManager] \(message)") } } } And ViewController import UIKit import SensorKit class ViewController: UIViewController { private var sensorManager: SensorManager! override func viewDidLoad() { super.viewDidLoad() setupSensorManager() } private func setupSensorManager() { sensorManager = SensorManager() sensorManager.delegate = self sensorManager.requestAuthorization() } } // MARK: - SensorManagerDelegate extension ViewController: SensorManagerDelegate { func didFetchPhoneUsageReport(_ reports: [SRPhoneUsageReport]) { for report in reports { print("Total Calls: (report.totalOutgoingCalls + report.totalIncomingCalls)") print("Outgoing Calls: (report.totalOutgoingCalls)") print("Incoming Calls: (report.totalIncomingCalls)") print("Total Call Duration: (report.totalPhoneCallDuration) seconds") } } func didFetchAmbientLightSensorData(_ data: [SRAmbientLightSample]) { for sample in data { print(sample) } } func didFailFetchingData(error: Error) { print("Failed to fetch data: \(error.localizedDescription)") } } Could anyone please assist me in resolving this issue? Any guidance or troubleshooting steps would be greatly appreciated.
0
0
176
Mar ’25
Arabic Text Appears Reversed and Broken in SwiftUI Lists, TextFields, and Pickers
Hello, I would like to report a critical issue with Arabic text rendering in SwiftUI apps on iOS and iPadOS. When using Arabic as the default language (Right-to-Left - RTL), Arabic text appears reversed and disconnected inside several SwiftUI components like: List Section TextField Picker Custom views (like StudentRowView) Even though the environment is set to .layoutDirection(.rightToLeft), the dynamic Arabic text is not rendered properly. Static headers display correctly, but any dynamic content (student names, notes, field titles) becomes broken and unreadable. Examples where the issue occurs: AboutView.swift → Arabic text inside List and Section SettingsView.swift → TextField placeholders and Picker options StudentRowView.swift → Student names and grade field titles Environment: SwiftUI 5 (Xcode 15+) iOS 17+ Reproducible 100% on both Simulator and real devices. Expected Behavior: Arabic text should appear properly connected, right-aligned, and readable without any manual workaround for each Text or TextField. Workarounds Tried: Manually setting .multilineTextAlignment(.trailing) (inefficient) Wrapping every Text inside an HStack with Spacer (hacky) Building custom UIKit views (defeats purpose of SwiftUI simplicity) Formal Feedback: I have submitted a Feedback Assistant report We hope this issue will be prioritized and fixed to improve SwiftUI's support for Arabic and other RTL languages. Thank you.
1
0
159
Apr ’25
How to truncate text from head with multi line?
I want to truncate text from head with max 2 lines. I try the following code import SwiftUI struct ContentView: View { @State var content: String = "Hello world! wef wefwwfe wfewe weweffwefwwfwe wfwe" var body: some View { VStack { Text(content) .lineLimit(nil) .truncationMode(.head) .frame(height: 50) Button { content += content } label: { Text("Double") } .buttonStyle(.borderedProminent) } .frame(width: 200, height: 1000) .padding() } } #Preview { ContentView() } It show result like this, this is not what I want.
0
0
247
Mar ’25
WidgetKit: add new widget to bundle
Hi, I have an existing Mac app on the App Store with a couple of widgets as part of the app. I want to now add a new widget to the WidgetBundle. When I build the updated app with Xcode, and then run the updated app, the widgets list doesn't seem to get updated in Notification Center or in the WidgetKit Simulator. I do have the App Store version installed in the /Applications folder as well, so there might be some conflict. What's the trick to getting the widgets list to run the debug version?
0
0
105
Mar ’25