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

Crash: KEY_TYPE_OF_DICTIONARY_VIOLATES_HASHABLE_REQUIREMENTS
Hi everyone, frome time to time I see crash which Im not able to debug, because there is no line of my code where crash occured. This is a crash log what Im getting from time to time of some users. In my device I never get this kind of crash. 0 libswiftCore.dylib 0x1172c _assertionFailure(_:_:flags:) + 208 1 libswiftCore.dylib 0x198624 KEY_TYPE_OF_DICTIONARY_VIOLATES_HASHABLE_REQUIREMENTS(_:) + 2980 2 libswiftCore.dylib 0xdb6c8 specialized _NativeDictionary.uncheckedRemove(at:isUnique:) + 534 3 libswiftCore.dylib 0xb250c Dictionary._Variant.setValue(_:forKey:) + 204 4 libswiftCore.dylib 0x5a620 Dictionary.subscript.setter + 520 5 SwiftUICore 0xf62ec ForEachState.item(at:offset:) + 4340 6 SwiftUICore 0xf5054 ForEachState.forEachItem(from:style:do:) + 1796 7 SwiftUICore 0x2272f8 ForEachState.traitKeys.getter + 84 8 SwiftUICore 0x227298 ForEachList.traitKeys.getter + 24 9 SwiftUICore 0x227008 protocol witness for ViewList.traitKeys.getter in conformance SubgraphList + 76 10 SwiftUICore 0x227008 protocol witness for ViewList.traitKeys.getter in conformance SubgraphList + 76 11 SwiftUICore 0x227008 protocol witness for ViewList.traitKeys.getter in conformance SubgraphList + 76 12 SwiftUICore 0x227008 protocol witness for ViewList.traitKeys.getter in conformance SubgraphList + 76 13 SwiftUICore 0x2271fc DynamicViewList.WrappedList.traitKeys.getter + 88 27 SwiftUICore 0x226d18 specialized static SectionAccumulator.processUnsectionedContent(list:contentSubgraph:) + 84 28 SwiftUI 0x26afe0 ListSectionInfo.init(list:listAttribute:contentSubgraph:) + 132 29 SwiftUI 0x269bb0 UpdateCollectionViewListCoordinator.updateValue() + 1528 30 SwiftUI 0x785d4 partial apply for implicit closure #1 in closure #1 in closure #1 in Attribute.init<A>(_:) + 32 31 AttributeGraph 0xccac AG::Graph::UpdateStack::update() + 540 32 AttributeGraph 0xc870 AG::Graph::update_attribute(AG::data::ptr<AG::Node>, unsigned int) + 424 33 AttributeGraph 0xc444 AG::Subgraph::update(unsigned int) + 848 34 SwiftUICore 0x805a8 GraphHost.flushTransactions() + 860 35 SwiftUI 0x1ac84 closure #1 in _UIHostingView._renderForTest(interval:) + 24 36 SwiftUICore 0x7ffa8 partial apply for closure #1 in ViewGraphDelegate.updateGraph<A>(body:) + 28 37 SwiftUICore 0x7fd6c ViewRendererHost.updateViewGraph<A>(body:) + 120 38 SwiftUICore 0x7fce8 ViewGraphDelegate.updateGraph<A>(body:) + 84 39 SwiftUI 0x3e688 closure #1 in closure #1 in closure #1 in _UIHostingView.beginTransaction() + 172 40 SwiftUI 0x3e5d4 partial apply for closure #1 in closure #1 in closure #1 in _UIHostingView.beginTransaction() + 24 41 SwiftUICore 0x79720 closure #1 in static Update.ensure<A>(_:) + 56 42 SwiftUICore 0x796a4 static Update.ensure<A>(_:) + 100 43 SwiftUI 0x9c808 partial apply for closure #1 in closure #1 in _UIHostingView.beginTransaction() + 80 44 SwiftUICore 0x7f5e0 thunk for @callee_guaranteed () -> () + 28 45 SwiftUICore 0x6161c specialized closure #1 in static NSRunLoop.addObserver(_:) + 144 46 CoreFoundation 0x218a4 __CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__ + 36 47 CoreFoundation 0x213f8 __CFRunLoopDoObservers + 552 48 CoreFoundation 0x75da8 __CFRunLoopRun + 948 49 CoreFoundation 0xc8284 CFRunLoopRunSpecific + 588 50 GraphicsServices 0x14c0 GSEventRunModal + 164 51 UIKitCore 0x3ee674 -[UIApplication _run] + 816 52 UIKitCore 0x14e88 UIApplicationMain + 340 53 SwiftUI 0x291ef8 closure #1 in KitRendererCommon(_:) + 168 54 SwiftUI 0x291e28 runApp<A>(_:) + 100 55 SwiftUI 0x291d0c static App.main() + 180 56 DholRainbow 0x3019e8 main + 4339145192 (DholRainbowApp.swift:4339145192) 57 ??? 0x1b0bf5de8 (Missing) From Crashlytics I know at least human readable format of this error Fatal error: Duplicate keys of type 'Contact' were found in a Dictionary. This usually means either that the type violates Hashable's requirements, or that members of such a dictionary were mutated after insertion. I 've checked all my parts of code where Im using dictionary. This is a function which creating that particulary dictionary. private func logsByDate() { let groupedByDate = Dictionary(grouping: logs.filter { ($0.remoteParty as? Contact != nil) } ) { $0.date.removeTimeStamp ?? .distantPast }.mapValues { $0.compactMap { $0 } } var dayLogs = [DayLog]() for date in groupedByDate { var contacts = [CallLogContact]() for log in logs.filter({ $0.date.removeTimeStamp ?? .distantPast == date.key }) { if let contact = log.remoteParty as? Contact { if contacts.firstIndex(where: {$0.contact == contact }) == nil { let contactDayLogs = logs.filter({ $0.remoteParty as? Contact == contact && $0.date.removeTimeStamp == date.key}) contacts.append( CallLogContact( contact: contact, logs: contactDayLogs, lastCallLogDate: contactDayLogs.sorted(by: {$0.date > $1.date}).first?.date ?? .distantPast ) ) } } } dayLogs.append(DayLog(date: date.key, contact: contacts)) } DispatchQueue.main.async { self.groupedCallLogs = dayLogs } } This function is called from 3 others functions based on notification from the server in case of new call log, fetched call logs and removed call logs.
0
0
294
Mar ’25
SensorKit Data Not Retrieving
I have received permission from Apple to access SensorKit data for my app. I have granted all necessary permissions, but no data is being retrieved. The didCompleteFetch method is being called, but I’m unsure where to find event data like Device Usage and Ambient Light. Additionally, the didFetchResult method is never called. Could anyone please assist me in resolving this issue? Any guidance or troubleshooting steps would be greatly appreciated. import SensorKit class ViewController: UIViewController, SRSensorReaderDelegate { let store = SRSensorReader(sensor: .deviceUsageReport) override func viewDidLoad() { super.viewDidLoad() requestSensorAuthorization() } func requestSensorAuthorization() { var sensors: Set<SRSensor> = [ .accelerometer, .deviceUsageReport, .messagesUsageReport, .visits, .keyboardMetrics, .phoneUsageReport, .ambientLightSensor ] if #available(iOS 16.4, *) { sensors.insert(.mediaEvents) } SRSensorReader.requestAuthorization(sensors: sensors) { error in if let error = error { print("Authorization failed: \(error.localizedDescription)") } else { self.store.startRecording() self.requestSensorData() print("Authorization granted for requested sensors.") } } } func requestSensorData() { let fromTime = SRAbsoluteTime.fromCFAbsoluteTime(_cf: Date().addingTimeInterval(-60 * 60).timeIntervalSinceReferenceDate) let toTime = SRAbsoluteTime.fromCFAbsoluteTime(_cf: Date().timeIntervalSinceReferenceDate) let request = SRFetchRequest() request.from = fromTime request.to = toTime request.device = SRDevice.current store.fetch(request) store.delegate = self } func sensorReader(_ reader: SRSensorReader, didCompleteFetch fetchRequest: SRFetchRequest) { print("Fetch request completed: \(fetchRequest.from) to \(fetchRequest.to)") Task { do { let samples = try await reader.fetch(fetchRequest) print("Samples count: \(samples)") } catch { print("Error Fetching Data: \(error.localizedDescription)") } } } func sensorReader(_ reader: SRSensorReader, fetching fetchRequest: SRFetchRequest, didFetchResult result: SRFetchResult<AnyObject>) -> Bool { print(result) return true } }
0
0
253
Mar ’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
399
Mar ’25
VisionOS custom hover effect and click sound
I have created a custom hover effect per this WWDC video and many other examples on the Net: https://developer.apple.com/videos/play/wwdc2024/10152/ I can get the button to expand when looked at within a VisionOS device and it will invoke a tap event when tapped but there is no click sound like a normal SwiftUI button does in VisionOS! I can't for the life of me figure out why. Any help would be appreciated!
2
0
298
Apr ’25
ObservableObjects get retained after a TextField is focused
When presenting a SwiftUI sheet containing ObservableObject's injected using environmentObject(_) modifier, the objects are unexpectedly retained after the sheet is dismissed if a TextField within the sheet gains focus or is edited. This issue occurs on iOS and iPadOS (on macOS the objects are always released), observable both in the simulator and on physical devices, and happens even when the view does not explicitly reference these environment objects, and the TextField's content isn't bound to them. Expected Results: When the sheet is dismissed, all environment objects passed to the sheet’s content view should be released (deinitialized), regardless of whether the TextField was focused or edited. Actual Results: If the TextField was focused or edited, environment objects (ObservableA and ObservableB) are retained after the sheet is dismissed. They are not deinitialized as expected, leading to unintended retention. Interestingly, previously retained copies of these environment objects, if any, are released precisely at the moment the TextField becomes focused on subsequent presentations, indicating an inconsistent lifecycle behavior. I have filed an issue FB17226970 Sample Code Below is a sample code that consistently shows the issue on iOS 18.3+. Steps to Reproduce: Run the attached SwiftUI sample. Tap the button labeled “Show Sheet” to present a sheet. Tap on the TextField to focus or begin editing. Dismiss the sheet by dragging it down or by other dismissal methods (e.g., tapping outside on iPadOS). import SwiftUI struct ContentView: View { @State private var showSheet: Bool = false var body: some View { VStack { Button("Show Sheet") { showSheet = true } } .sheet(isPresented: $showSheet) { SheetContentView() .environmentObject(ObservableA()) .environmentObject(ObservableB()) } } } struct SheetContentView: View { @State private var text: String = "" var body: some View { TextField("Select to retain observable objects", text: $text) .textFieldStyle(.roundedBorder) } } final class ObservableA: ObservableObject { init() { print(type(of: self), #function) } deinit { print(type(of: self), #function) } } final class ObservableB: ObservableObject { init() { print(type(of: self), #function) } deinit { print(type(of: self), #function) } } #Preview { ContentView() }
2
0
189
Apr ’25
VideoToolbox crash in macOS
My Mac app crashes for some users inside VideoToolbox, and I'm not sure what to do with that, and how to fix it. Here are couple of examples that repeating again and again for macOS 15.* Thread 10 Crashed: 0 libsystem_pthread.dylib 0x000000018535a8e0 0x185359000 + 6368 1 VideoToolbox 0x0000000194f3e218 0x194f28000 + 90648 2 VideoToolbox 0x00000001951de384 0x194f28000 + 2843524 3 libxpc.dylib 0x000000018506f2c0 0x185060000 + 62144 4 libxpc.dylib 0x000000018506da14 0x185060000 + 55828 5 libdispatch.dylib 0x00000001851ad674 0x1851a9000 + 18036 6 libdispatch.dylib 0x00000001851c9c88 0x1851a9000 + 134280 7 libdispatch.dylib 0x00000001851b4a38 0x1851a9000 + 47672 8 libdispatch.dylib 0x00000001851ca9dc 0x1851a9000 + 137692 9 libdispatch.dylib 0x00000001851b4a38 0x1851a9000 + 47672 10 libdispatch.dylib 0x00000001851b5764 0x1851a9000 + 51044 11 libdispatch.dylib 0x00000001851bf4cc 0x1851a9000 + 91340 12 libdispatch.dylib 0x00000001851bf260 0x1851a9000 + 90720 13 libsystem_pthread.dylib 0x00000001853602e4 0x185359000 + 29412 14 libsystem_pthread.dylib 0x000000018535b0fc 0x185359000 + 8444 and Thread 10 Crashed: 0 libsystem_pthread.dylib 0x00000001981fc364 0x1981fb000 + 4964 1 VideoToolbox 0x00000001a85f9964 0x1a81e8000 + 4266340 2 VideoToolbox 0x00000001a847a840 0x1a81e8000 + 2697280 3 libxpc.dylib 0x0000000197f09830 0x197efb000 + 59440 4 libxpc.dylib 0x0000000197f0812c 0x197efb000 + 53548 5 libdispatch.dylib 0x00000001980638a4 0x198048000 + 112804 6 libdispatch.dylib 0x00000001980660e8 0x198048000 + 123112 7 libdispatch.dylib 0x00000001980521b8 0x198048000 + 41400 8 libdispatch.dylib 0x0000000198066e4c 0x198048000 + 126540 9 libdispatch.dylib 0x00000001980521b8 0x198048000 + 41400 10 libdispatch.dylib 0x0000000198052e60 0x198048000 + 44640 11 libdispatch.dylib 0x000000019805be30 0x198048000 + 81456 12 libdispatch.dylib 0x000000019805bbf0 0x198048000 + 80880 13 libsystem_pthread.dylib 0x0000000198201c0c 0x1981fb000 + 27660 14 libsystem_pthread.dylib 0x00000001981fcb80 0x1981fb000 + 7040 and this one is for macOS 14 Thread 10 Crashed: 0 VideoToolbox 0x000000018f12ac90 0x18f11d000 + 56464 1 VideoToolbox 0x000000018f130a80 0x18f11d000 + 80512 2 VideoToolbox 0x000000018f131090 0x18f11d000 + 82064 3 VideoToolbox 0x000000018f130f94 0x18f11d000 + 81812 4 Remote for Mac 0x00000001048d521c 0x1048d0000 + 21020 5 Foundation 0x000000018174796c 0x181709000 + 256364 6 Foundation 0x000000018174782c 0x181709000 + 256044 7 Foundation 0x00000001817477bc 0x181709000 + 255932 8 Foundation 0x0000000181746b64 0x181709000 + 252772 9 Foundation 0x00000001817468d4 0x181709000 + 252116 10 Foundation 0x00000001817467c4 0x181709000 + 251844 11 libdispatch.dylib 0x00000001803b0470 0x18039d000 + 78960 12 libdispatch.dylib 0x00000001803a13e8 0x18039d000 + 17384 13 libdispatch.dylib 0x00000001803a48ec 0x18039d000 + 30956 14 libdispatch.dylib 0x00000001803a3f08 0x18039d000 + 28424 15 libdispatch.dylib 0x00000001803b2ea8 0x18039d000 + 89768 16 libdispatch.dylib 0x00000001803b36b8 0x18039d000 + 91832 17 libsystem_pthread.dylib 0x000000018054dfd0 0x18054b000 + 12240 18 libsystem_pthread.dylib 0x000000018054cd28 0x18054b000 + 7464
0
0
142
Apr ’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
93
Mar ’25
SwiftUI Button fade animation happens with a delay when in ScrollView
When we place a Button inside a ScrollView , the fade animation of the button is delayed, so most users won't see it I think. You can see this in the trivial example struct ContentView: View { var body: some View { ScrollView { Button { // empty } label: { Text("Fade animation test") } } } } Is there any way to opt out of this behavior? In UIKit, this was also the default behavior, but you could always change it by overriding touchesShouldCancel method. I think I can probably do that by rewriting an animation completely with some custom ButtonStyle or by rewriting a Button component completely, but it doesn't seem like a good solution to me, as I want the native look and feel (in case of button animation it is pretty easy to mimic though). And also for some components, like lists, Apple has already implemented the correct behavior by themselves somehow.
3
0
100
Apr ’25
Buttons in menu don't respect the environment value of .layoutDirection in SwiftUI
Problem Setting ".environment(.layoutDirection, .rightToLeft)" to a view programmatically won't make buttons in menu to show right to left. However, setting ".environment(.locale, .init(identifier: "he-IL"))" to a view programmatically makes buttons in menu to show Hebrew strings correctly. Development environment: Xcode 16.x, macOS 15.3.1 Target iOS: iOS 17 - iOS 18 The expected result is that the button in the menu should be displayed as an icon then a text from left to right. Code to demonstrate the problem: struct ContentView: View { var body: some View { VStack(alignment: .leading) { Text("Buttons in menu don't respect the environment value of .layoutDirection") .font(.subheadline) .padding(.bottom, 48) /// This button respects both "he-IL" of ".locale" and ".rightToLeft" of ".layoutDirection". Button { print("Button tapped") } label: { HStack { Text("Send") Image(systemName: "paperplane") } } Menu { /// This button respects "he-IL" of ".locale" but doesn't respect ".rightToLeft" of ".layoutDirection". Button { print("Button tapped") } label: { HStack { Text("Send") Image(systemName: "paperplane") } } } label: { Text("Menu") } } .padding() .environment(\.locale, .init(identifier: "he-IL")) .environment(\.layoutDirection, .rightToLeft) } }
4
0
89
Mar ’25
SwiftUI + OSlog breaks previews in Swift 6
import SwiftUI import OsLog let logger = Logger(subsystem: "Test", category: "Test") struct ContentView: View { var body: some View { VStack { Image(systemName: "globe") .imageScale(.large) .foregroundStyle(.tint) Text("Hello, world!") } .padding() .task { logger.info("Hallo") } } } #Preview { ContentView() } 27 | .padding() 28 | .task { 29 | logger.info(__designTimeString("#6734_2", fallback: "Hallo")) | `- error: argument must be a string interpolation 30 | } 31 | } Should OsLog be compatible with __designTimeString?
1
0
137
Mar ’25
progress view does not work
I have an app that run Monte Carlo simulations. I run thousands of simulations in the app and a simulation runs can take on the order of 30 seconds to a minute to complete. I would like to have a progress view that tracks the number of simulation runs. How can I implement this in swiftui?
0
0
175
Mar ’25
UIScrollView in UIViewControllerRepresentable - UI freezes when content touches bottom SafeArea
The SwiftUI ScrollView lacks some features I need and so I created a custom MyScrollView based on UIScrollView wrapped within a UIViewControllerRepresentable. While this works fine in general I know came across a very strange problem: When MyScrollView is used in a sheet and its content touches bottom SafeArea, the UI freezes as soon as the should be displayed. The code below shows the problem as well in preview as on the simulator and on devices. Please note that the code is tuned do the display size of an iPhone 16 Pro. When running on different devices one might need to adjust height of the Color.yellow. In the demo code the UI freezes if the Color.yellow has a height between 738 to 771 pixels. Every other height is fine. Is there something wrong with my implementation of MyScrollView? When using ScrollView instead, everything works fine. Code: struct ContentView: View { @State private var showSheet: Bool = false var body: some View { ZStack { Button("Show Sheet") { showSheet = true } } .sheet(isPresented: $showSheet) { VStack { Text("Some Header Content") MyScrollView { VStack { Color.yellow //.frame(height: 737) // works .frame(height: 738) // does NOT works // ... //.frame(height: 771) // does NOT works //.frame(height: 772) // works } } .ignoresSafeArea() } } } } struct MyScrollView<Content: View>: UIViewControllerRepresentable { let content: Content init(@ViewBuilder content: () -> Content) { self.content = content() } func makeUIViewController(context: Context) -> UIViewController { let scrollViewVC = UIViewController() scrollViewVC.view.backgroundColor = .clear let scrollView = UIScrollView() scrollView.backgroundColor = .clear let contentVC = UIHostingController(rootView: self.content) contentVC.view.backgroundColor = .clear context.coordinator.contentVC = contentVC context.coordinator.scrollView = scrollView scrollView.translatesAutoresizingMaskIntoConstraints = false scrollViewVC.view.addSubview(scrollView) NSLayoutConstraint.activate([ scrollView.topAnchor.constraint(equalTo: scrollViewVC.view.topAnchor), scrollView.bottomAnchor.constraint(equalTo: scrollViewVC.view.bottomAnchor), scrollView.leadingAnchor.constraint(equalTo: scrollViewVC.view.leadingAnchor), scrollView.trailingAnchor.constraint(equalTo: scrollViewVC.view.trailingAnchor) ]) contentVC.willMove(toParent: scrollViewVC) scrollViewVC.addChild(contentVC) contentVC.view.translatesAutoresizingMaskIntoConstraints = false scrollView.addSubview(contentVC.view) NSLayoutConstraint.activate([ contentVC.view.topAnchor.constraint(equalTo: scrollView.contentLayoutGuide.topAnchor), contentVC.view.bottomAnchor.constraint(equalTo: scrollView.contentLayoutGuide.bottomAnchor), contentVC.view.leadingAnchor.constraint(equalTo: scrollView.contentLayoutGuide.leadingAnchor), contentVC.view.trailingAnchor.constraint(equalTo: scrollView.contentLayoutGuide.trailingAnchor), contentVC.view.widthAnchor.constraint(equalTo: scrollView.frameLayoutGuide.widthAnchor) ]) contentVC.didMove(toParent: scrollViewVC) return scrollViewVC } func updateUIViewController(_ uiViewController: UIViewController, context: Context) { context.coordinator.contentVC?.rootView = content } func makeCoordinator() -> Coordinator { return Coordinator() } class Coordinator { var contentVC: UIHostingController<Content>? var scrollView: UIScrollView? init() { //... } } } #Preview { ContentView() }
Topic: UI Frameworks SubTopic: SwiftUI
2
0
112
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
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
252
Mar ’25
Seeking KeyboardLayout ID for All Native Keyboards in iOS and macOS
Hello everyone, I am currently working on a project that requires me to programmatically manage keyboard layouts on both iOS and macOS devices. I'm looking for a comprehensive list of KeyboardLayout ID values for all the native keyboard layouts available in both iOS and macOS. While I can extract some of this information from the /System/Library/Keyboard Layouts/ directory on macOS, I cannot extract all without adding every keyboard layout active, having a complete and pre-compiled list would be immensely helpful. Does anyone here have such a list or know where I might find one? Any guidance on this matter would be greatly appreciated. Thank you in advance for your assistance! JJ
4
0
980
Mar ’25
searchable isPresented set too late in a sheet
I have a popover/sheet in iOS which allows users to search and add items to a list. When the sheet is shown, the search should always be active. I am using searchable on a NavigationStack inside the sheet. I am using the isPresented parameter to activate search. My issue is with the animation of the search activation. Even if I use... isPresented: .constant(true) ...the search isn't activated until the sheet has completed it's entrance animation, resulting in two stages of animation. I can't add a video here, but the two images below show the steps I am seeing. First a slide up animation, with the search in the navigation drawer, then a second animation, once the sheet is fully in place, as the search becomes active. Is it possible to merge these two animations, so search is in place when the sheet animates up?
Topic: UI Frameworks SubTopic: SwiftUI
0
0
51
Apr ’25
Vibrancy effect not applied to context menu UIImages rendered in template mode
Our Apple TV provides UIImages with renderingMode forced to .alwaysTemplate (the images are also configured with "Render As" to "Template image" in the Asset catalog) to UIActions as UIMenuElement when building a UICollectionView UIContextMenuConfiguration. Problem: these images are not displayed with vibrancy effect by the system. The issue does not occur with system images (SVG from SF Catalog). Here is a screenshot showing the issue with custom images ("Trailer" and "Remove from favourites"): I don't know the underlying implementation of the context menu items image but UIImageView already implements the tintColorDidChange() method and the vibrancy should work if the UIImage is rendered as template. According to my tests, the vibrancy is correctly applied when using Symbols sets instead of Images sets but I understand that custom images rendered as template should support it as-well, shouldn't they?
2
0
201
Mar ’25
CarPlay Question
Why is there no option as a CarPlay developer to enable the creation of an App to track and enter your car's maintenance records? I know the pat reply would be Apple doesn't want you to do this while car is in motion. But I would normally do this while parked at the dealership or other service provider no?
1
0
302
Mar ’25
Hover effect in Custom UIKit Views
I am adapting my custom UI Framework for visionOS, and I'm wondering if it is going to be possible to detect hover over different UI elements within my view. The UI Framework draws to a Metal layer in a UIView. I don't currently support uihovergesturerecognizer on the view but I guess this wouldn't help, since you don't get coordinates. I can imagine an unpleasant solution might be to add invisible UIControls for each of my custom controls that are drawn in my own framework.
1
0
62
Apr ’25
NSLayoutManager returning inconsistent values for a glyph's text container and its line fragment rect
TLDR: NSLayoutManager's textContainer(forGlyphAt:effectiveRange:) and lineFragmentRect(forGlyphRange:effectiveRange:) are returning inconsistent results. Context: I'm developing a word processing app that paginates from an NSTextStorage using NSLayoutManager. My app uses a text attribute (.columnType) to paginate sub-ranges of the text at a time, ensuring that each columnRange gets a container (or series of containers across page breaks) to fit. This is to support both multi-column and standard full-page-width content. After any user edit, I update pagination data in my Paginator model class. I calcuate frames/sizes for the views/containers, along with what superview they belong to (page). The UI updates accordingly. In order to determine whether the columnRange has overflowed from a container due to a page break OR whether the range of text hasn't overflowed its container and is actually using less space than available and should be sized down, I call both: layoutManager.textContainer(forGlyphAt: lastGlyphOfColumn, effectiveRange: &actualGlyphRangeInContainer)` // and `layoutManager.lineFragmentRect(forGlyphAt: lastGlyphOfColumn, effectiveRange: nil) Apple Documentation notes that both these calls force glyph generation and layout. As I'm in early development, I have not set non-contiguous layout. So these should be causing full layout, assuring accurate return values. Or so I'd hoped. This does work fine in many cases. I edit. Pagination works. But then I'll encounter UI-breaking inconsistent returns from these two calls. By inconsistent, I mean that the second call returns a line fragment rect that is in the container coordinates of A DIFFERENT container than the container returned by the first call. To be specific, the line fragment rect seems to be in the coordinates of the container that comes next in layoutManager.textContainers. Example Code: if !layoutManager.textContainers.indices.contains(i) { containerToUse = createTextContainer(with: availableSize) layoutManager.addTextContainer(containerToUse) } else { // We have a container already but it may be // the wrong size. containerToUse = layoutManager.textContainers[i] if containerToUse.size.width != availableSize.width { // Mandatory that we resize if we don't have // a matching width. Height resizing is not // mandatory and requires a layout check below. containerToUse.size = availableSize } } let glyphRange = layoutManager.glyphRange(forCharacterRange: remainingColumnRange, actualCharacterRange: nil) let lastGlyphOfColumn = NSMaxRange(glyphRange) - 1 var containerForLastGlyphOfColumn = layoutManager.textContainer(forGlyphAt: lastGlyphOfColumn, effectiveRange: &actualGlyphRangeInContainer) if containerForLastGlyphOfColumn != containerToUse && containerToUse.size.height < availableSize.height { // If we are here, we overflowed the container, // BUT the container we overflowed didn't use // the maximum remaining page space (this // means it was a pre-existing container that // needs to be sized up and checked once more). // NOTE RE: THE BUG: // at this point, prints show... // containerToUse.size.height // =628 // availableSize.height // =648 containerToUse.size = availableSize containerForLastGlyphOfColumn = layoutManager.textContainer(forGlyphAt: lastGlyphOfColumn, effectiveRange: &actualGlyphRangeInContainer) } // We now check again, knowing that the container we // are testing flow into is the max size it can be. if containerForLastGlyphOfColumn != containerToUse { // If we are here, we have overflowed the // container, so containerToUse size SHOULD be // final/accurate, since it is fully used. actualCharRangeInContainer = layoutManager.characterRange(forGlyphRange: actualGlyphRangeInContainer, actualGlyphRange: nil) // Start of overflow range is the first character // in the container that was overflowed into. let overflowLoc = actualCharRangeInContainer.location remainingColumnRange = NSRange(location: overflowLoc, length: remainingColumnRange.length - overflowLoc) // Update page count as we have broken to a new page currentPage += 1 } else { // If we are here, we have NOT overflowed // from the container. BUT... // THE BUG: // ***** HERE IS THE BUG! ***** lineFragmentRectForLastChar = layoutManager.lineFragmentRect(forGlyphAt: lastGlyphOfColumn, effectiveRange: nil) let usedHeight = lineFragmentRectForLastChar.maxY // BUG: ^The lines of code above return a // fragment rect that is in the coordinates // of the WRONG text container. Prints show: // usedHeight // =14 // usedHeight shouldn't be just 14 if this is // the SAME container that, when it was 628 // high, resulted in text overflowing. // Therefore, the line fragment here seems // to be in the coordinates of the ENSUING // container that we overflowed INTO, but // that shouldn't be possible, since we're in // a closure for which we know: // // containerForLastGlyphOfColumn == containerToUse // // If the last glyph container is the container // we just had to size UP, why does the final // glyph line fragment rect have a maxY of 14!? // Including ensuing code below only for context. if usedHeight < containerToUse.size.height { // Adjust container size down to usedRect containerToUse.size = CGSize(width: containerToUse.size.width, height: usedHeight) } else if usedHeight == availableSize.height { // We didn't force break to a new page BUT // we've used exactly the height of our page // to layout this column range, so need to // break to a new page for any ensuing text // columns. currentPage += 1 } else if usedHeight > containerToUse.size.height { // We should have caught this earlier. Text // has overflowed, but this should've been // caught when we checked // containerForLastGlyphOfColumn != // containerToUse. // // Note: this error has never thrown. throw PaginationError.unknownError("Oops.") } } Per my comments in the code block above, I don't understand why the very same text container that just overflowed and so had to be sized up from 628 to 648 in order to try to fit a glyph would now report that same glyph as both being IN that same container and having a line fragment rect with a maxY of just 14. A glyph couldn't fit in a container when it was 628 high, but if I size it up to 648, it only needs 14? There's something very weird going on here. Working with NSLayoutManager is a bit of a nightmare given the unclear documentation. Any help or insight here would be massively, massively appreciated.
2
0
512
Apr ’25