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

Hover effect is shown on a disabled button
Hello. I have a scenario where a hover effect is being shown for a button that is disabled. Usually this doesn't happen but when you wrap the button in a Menu it doesn't work properly. Here is some example code: struct ContentView: View { var body: some View { NavigationStack { Color.green .toolbar { ToolbarItem(placement: .topBarTrailing) { Menu("Menu") { Button("Disabled Button") {} .disabled(true) .hoverEffectDisabled() // This doesn't work. Button("Enabled Button") {} } } } } } } And here is what it looks like: This looks like a SwiftUI bug. Any help is appreciated, thank you!
1
0
267
Feb ’25
Will [NSEvent setMouseCoalescingEnabled:NO] even work in Swift?
In a macOS Swift app I'm trying to get mouse events to not coalesce. This used to work in an Obj-C app by calling [NSEvent setMouseCoalescingEnabled:NO]. setMouseCoalescingEnabled is not exposed in the Swift version of NSEvent. I built a bridge over to a .mm file that calls [NSEvent setMouseCoalescingEnabled:NO] and checked NSEvent.isMouseCoalescingEnabled in Swift after calling and it returns false saying that coalescing is disabled. The mouse is still skipping points (func mouseDragged(with theEvent: NSEvent)) when it is dragged across the window fast. I'm calling [NSEvent setMouseCoalescingEnabled:NO] in applicationDidFinishLaunching().
Topic: UI Frameworks SubTopic: AppKit
1
0
371
Feb ’25
Crash on Sequoia 15.2
Starting from Sequoia release 15.2 apps crash with following call stack, when adding static text controls. First call to [NSTextField setStringValue] causes following crash 0 libobjc.A.dylib 0x19f2f5820 objc_msgSend + 32 1 AppKit 0x1a3355460 -[NSCell _objectValue:forString:errorDescription:] + 144 2 AppKit 0x1a3355348 -[NSCell setStringValue:] + 48 3 AppKit 0x1a33af9fc -[NSControl setStringValue:] + 104 4 AppKit 0x1a3d1f190 -[NSTextField setStringValue:] + 52 It happens on specific MacBook Pro models(16 in MacBook Pro). Crash analysis found that isa pointer of the object was corrupted for the object NSCell. Enabled Zombies in debugging, not found any issue. Also tried address sanitizer. Since the issue started with a recent release of macOS, any changes in the Appkit in the recent releases trigger the crash? Any help/suggestions would be appreciated.
Topic: UI Frameworks SubTopic: AppKit
4
0
401
Feb ’25
Xcode 15 Breaks Usage Of TextField.focused()
My usage of TextField.focused() works fine in Xcode 14.3.1 but is broken as of Xcode 15. I first noticed it in the second beta and it's still broken as of the 4th beta. Feedback / OpenRadar # FB12432084 import SwiftUI struct ContentView: View { @State private var text = "" @FocusState var isFocused: Bool var body: some View { ScrollView { TextField("Test", text: $text) .textFieldStyle(.roundedBorder) .focused($isFocused) Text("Text Field Is Focused: \(isFocused.description)") } } }
7
1
1.7k
Feb ’25
isPressed is not reliable when Button is inside ScrollView
I opened a feedback ticket (FB16508762) but maybe someone in the community already found a workaround while the feedback reaches the maintainers. When I put a Button inside a ScrollView, the tap animation stops working reliably and works only when the user taps and holds the button for a short time. The reasons, I believe is related to the fact that isPressed of configuration does not change and the default button styles use it to animate the tap. import SwiftUI struct DebuggingButtonStyle: ButtonStyle { func makeBody(configuration: Configuration) -> some View { configuration.label .onChange(of: configuration.isPressed, { oldValue, newValue in print("Is pressed: \(oldValue) -> \(newValue)") }) } } struct ContentView: View { var body: some View { VStack { Text("Buttons inside scroll view respond to taps as expected, however isPessed value of the configuration do not change unless the user press and hold it. Try to press the promiment button quickly or use the debug button and observe the console log.") ScrollView { VStack { Button("Button Inside ScrollView") { print("Button tapped") } .buttonStyle(.borderedProminent) Button("Button Inside ScrollView (printing isPressed)") { print("Button tapped") } .buttonStyle(DebuggingButtonStyle()) } } .border(FillShapeStyle(), width: 2) Spacer() Text("For reference, here is a button outside of a ScrollView. Tap the promiment button to observe how the button is expected to animate in respnse to a press.") VStack { Button("Button Outside ScrollView") { print("Button tapped") } .buttonStyle(.borderedProminent) Button("Button Outside ScrollView (printing isPressed)") { print("Button tapped") } .buttonStyle(DebuggingButtonStyle()) } } .padding() } }
1
4
457
Feb ’25
SwiftData with shared and private containers
I was hoping for an update of SwiftData which adopted the use of shared and public CloudKit containers, in the same way it does for the private CloudKit container. So firstly, a big request to any Apple devs reading, for this to be a thing! Secondly, what would be a sensible way of adding a shared container in CloudKit to an existing app that is already using SwiftData? Would it be possible to use the new DataStore method to manage CloudKit syncing with a public or shared container?
11
18
3.8k
Feb ’25
URL passed as attachment to notification is deleted when notification is added
I create a notification with an image attachment: let center = UNUserNotificationCenter.current() center.delegate = self let content = UNMutableNotificationContent() // some more stuff… let paths = NSSearchPathForDirectoriesInDomains( FileManager.SearchPathDirectory.documentDirectory, FileManager.SearchPathDomainMask.userDomainMask, true) let documentsDirectory = paths[0] as NSString let fileExtPNG = "#" + "\(imageName)" + " photo.png" let fileNamePNG = documentsDirectory.appendingPathComponent(fileExtPNG) as String url = URL(fileURLWithPath: fileNamePNG) let attachment = try UNNotificationAttachment(identifier: "Image", url: url, options: nil) content.attachments = [attachment] I then add the request: let request = UNNotificationRequest(identifier:requestIdentifier, content: content, trigger: nil) center.removePendingNotificationRequests(withIdentifiers: [requestIdentifier]) center.add(request) {(error) in } Problem: when I later test (once notification has been registered), the file do not exist anymore at the url. I've commented out the add request to confirm. I have a work around, by creating a temporary copy of the file at the URL and pass it in the attachment. Then, everything works fine and the copy is deleted. But that's a bit bizarre. What am I missing here ?
2
0
387
Feb ’25
[iOS, SwiftUI] Navigation Bar background is always hidden when navigation destination is TabView
Hello! I have a destination navigation which is TabVIew where each tab item is ScrollView. And when scrolling content of any of tab items is underneath navigation bar its background is always hidden. But at the same time tab bar background is toggled depending on scrolling content position. I expected it would work with TabView the same as with any other view. Is it supposed to work like that?
2
0
326
Feb ’25
CollectionView: Sync `center.y` of UIView outside collection view and a view in a cellinside
I have a setup: Collection view with compositional layout a self sizing cell inside a subview inside the cell and unrelated view outside the collection view I would like to: modify the layout (constraints) of the cell inside the collection view with UIView.animate trigger an animated layout update of collection view synchronize the position of an unrelated view to the position of one of the subviews of a collection view cell What I tried: UIView.animate(withDuration: 0.25) { cellViewReference.updateState(state: state, animated: false) collectionView.collectionViewLayout.invalidateLayout() collectionView.layoutIfNeeded() someOtherViewOutsideCollectionView.center = cellViewReference.getPositionOfThatOneViewInWindowCoordinateSystem() } What I'm expecting: after invalidateLayout, the layout update of the collection view is merely scheduled, but not yet performed layoutIfNeeded forces an update on the collectionViewLayout + update on the frames of the views inside the UICollectionViewCells all the frames become correct to what they will look like after the animation is performed I call getPositionOfThatOneViewInWindowCoordinateSystem and it gives me the position of the view after the uicollectionview AND the cell's layout has updated What happens instead: getPositionOfThatOneViewInWindowCoordinateSystem returns me an old value I am observing that the bounds of the cell didn't actually change during layoutIfNeeded And moreover, the bounds change without animation, instantly Question: how to animate self sizing cell size change due relayout how to synchronize outside views with collection views
Topic: UI Frameworks SubTopic: UIKit Tags:
1
0
282
Feb ’25
Signal SIGABRT on accessing values from SwiftData query
I work on an iOS app using SwiftUI and SwiftData. I added a computed property to one of my models - Parent - that uses relationship - array of Child models - data and I started getting strange problems. Let me start with models: @Model final class Parent { var name: String @Relationship(deleteRule: .cascade, inverse: \Child.parent) var children: [Child]? = [] var streak: Int { // Yes, I know that's not optimal solution for such counter ;) guard let children = children?.sorted(using: SortDescriptor(\.date, order: .reverse)) else { return 0 } var date = Date.now let calendar = Calendar.current for (index, child) in children.enumerated() { if !calendar.isDate(child.date, inSameDayAs: date) { return index } date = calendar.date(byAdding: .day, value: -1, to: date) ?? .now } return children.count } init(name: String) { self.name = name } } @Model final class Child { var date: Date @Relationship(deleteRule: .nullify) var parent: Parent? init(date: Date, parent: Parent) { self.date = date self.parent = parent } } At first everything works as expected. The problem arises once I try to remove one of child from the parent instance. I remove the value from context and save changes without any problems, at least not ones that can be caught by do { } catch. But instead of refreshing UI I get an signal SIGABRT somewhere inside SwiftData internals that points to the line where I'm trying (inside View body) get a child from a Query: struct LastSevenDaysButtons: View { @Environment(\.modelContext) private var modelContext @Query private var children: [Child] private let dates: [Date] private let parent: Parent init(for parent: Parent) { self.parent = parent var lastSevenDays = [Date]() let calendar = Calendar.current let firstDate = calendar.date(byAdding: .day, value: -6, to: calendar.startOfDay(for: .now)) ?? .now var date = firstDate while date <= .now { lastSevenDays.append(date) date = calendar.date(byAdding: .day, value: 1, to: date) ?? .now } dates = lastSevenDays let parentId = parent.persistentModelID _children = Query( filter: #Predicate { $0.parent?.persistentModelID == parentId && $0.date >= firstDate }, sort: [SortDescriptor(\Child.date, order: .reverse)], animation: .default ) } var body: some View { VStack { HStack(alignment: .top) { ForEach(dates, id: \.self) { date in // Here is the last point on stack from my code that I see let child = children.first { $0.date == date } Button { if let child { modelContext.delete(child) } else { modelContext.insert(Child(date: date, parent: parent)) } do { try modelContext.save() } catch { print("Can't save changes for \(parent.name) on \(date.formatted(date: .abbreviated, time: .omitted)): \(error.localizedDescription)") } } label: { Text("\(date.formatted(date: .abbreviated, time: .omitted))") .foregroundStyle(child == nil ? .red : .blue) } } } } } } The LastSevenDaysButtons View is kind of deep in a View hierarchy: RootView -> ParentList -> ParentListItem -> LastSevenDaysButtons However once I move insides of ParentList to RootView application works just fine, although I see and warning: === AttributeGraph: cycle detected through attribute 6912 ===. What could be that I do wrong in here? I believe it must something I'm missing here, but after 2 days of debug, trial and errors, I can't think clearly anymore. Here is the minimal repro I managed to create: Signal SIGABRT on accessing values from SwiftData query
3
0
751
Feb ’25
Crash when rendering CALayer using UIGraphicsImageRenderer on background thread
Hello! I’m experiencing a crash in my iOS/iPadOS app related to a CALayer rendering process. The crash occurs when attempting to render a UIImage on a background thread. The crashes are occurring in our production app, and while we can monitor them through Crashlytics, we are unable to reproduce the issue in our development environment. Relevant Code I have a custom view controller that handles rendering CALayers onto images. This method creates a CALayer on the main thread and then starts a detached task to render this CALayer into a UIImage. The whole idea is learnt from this StackOverflow post: https://stackoverflow.com/a/77834613/9202699 Here are key parts of my implementation: class MyViewController: UIViewController { @MainActor func renderToUIImage(size: CGSize, itemsToDraw: [MyDrawingItem], transform: CGAffineTransform) async -> UIImage? { // Create CALayer and add it to the view. CATransaction.begin() let customLayer = MyDrawingLayer() customLayer.setupContent(itemsToDraw: itemsToDraw) // Position the frame off-screen to it hidden. customLayer.frame = CGRect( origin: CGPoint(x: -100 - size.width, y: -100 - size.height), size: size) customLayer.masksToBounds = true customLayer.drawsAsynchronously = true view.layer.addSublayer(customLayer) CATransaction.commit() // Render CALayer to UIImage in background thread. let image = await Task.detached { customLayer.setNeedsDisplay() let renderer = UIGraphicsImageRenderer(size: size) let image = renderer.image { // CRASH happens on this line let cgContext = $0.cgContext cgContext.saveGState() cgContext.concatenate(transform) customLayer.render(in: cgContext) cgContext.restoreGState() } return image }.value // Remove the CALayer from the view. CATransaction.begin() customLayer.removeFromSuperlayer() CATransaction.commit() return image } } class MyDrawingLayer: CALayer { var itemsToDraw: [MyDrawingItem] = [] func setupContent(itemsToDraw: [MyDrawingItem]) { self.itemsToDraw = itemsToDraw } override func draw(in ctx: CGContext) { for item in itemsToDraw { // Render the item to the context (example pseudo-code). // All items are thread-safe to use. // Things to draw may include CGPath, CGImages, UIImages, NSAttributedString, etc. item.draw(in: ctx) } } } Crash Log The crash occurs at the following location: Crashed: com.apple.root.default-qos.cooperative 0 MyApp 0x5cb300 closure #1 in closure #1 in MyViewController.renderToUIImage(size: CGSize, itemsToDraw: [MyDrawingItem], transform: CGAffineTransform) + 4313002752 (<compiler-generated>:4313002752) 1 MyApp 0x5cb300 closure #1 in closure #1 in MyViewController.renderToUIImage(size: CGSize, itemsToDraw: [MyDrawingItem], transform: CGAffineTransform) + 4313002752 (<compiler-generated>:4313002752) 2 MyApp 0x1a4578 AnyModifier.modified(for:) + 4308649336 (<compiler-generated>:4308649336) 3 MyApp 0x7b4e64 thunk for @escaping @callee_guaranteed (@guaranteed UIGraphicsPDFRendererContext) -> () + 4315008612 (<compiler-generated>:4315008612) 4 UIKitCore 0x1489c0 -[UIGraphicsRenderer runDrawingActions:completionActions:format:error:] + 324 5 UIKitCore 0x14884c -[UIGraphicsRenderer runDrawingActions:completionActions:error:] + 92 6 UIKitCore 0x148778 -[UIGraphicsImageRenderer imageWithActions:] + 184 7 MyApp 0x5cb1c0 closure #1 in MyViewController.renderToUIImage(size: CGSize, itemsToDraw: [MyDrawingItem], transform: CGAffineTransform) + 100 (FileName.swift:100) 8 libswift_Concurrency.dylib 0x60f5c swift::runJobInEstablishedExecutorContext(swift::Job*) + 252 9 libswift_Concurrency.dylib 0x62514 swift_job_runImpl(swift::Job*, swift::SerialExecutorRef) + 144 10 libdispatch.dylib 0x15ec0 _dispatch_root_queue_drain + 392 11 libdispatch.dylib 0x166c4 _dispatch_worker_thread2 + 156 12 libsystem_pthread.dylib 0x3644 _pthread_wqthread + 228 13 libsystem_pthread.dylib 0x1474 start_wqthread + 8 Questions Is it safe to run UIGraphicsImageRenderer.image on the background thread? Given that I want to leverage GPU rendering, what are some best practices for rendering images off the main thread while ensuring stability? Are there alternatives to using UIGraphicsImageRenderer for background rendering that can still take advantage of GPU rendering? It is particularly interesting that the crash logs indicate the error may be related to UIGraphicsPDFRendererContext (crash log line number 3). It would be very helpful if someone could explain the connection between starting and drawing on a UIGraphicsImageRenderer and UIGraphicsPDFRendererContext. Any insights or guidance on this issue would be greatly appreciated. Thanks!!!
1
0
612
Feb ’25
Navigation Stack Zoom Transition – Title Animation Issue
SwiftUI Navigation Stack Zoom Transition – Title Animation Issue (iOS 18) In the WWDC24 video "Enhance your UI animations and transitions", Apple demonstrates how the navigation stack title smoothly animates into the back button in the new view when using a zoom transition: NavigationLink { BraceletEditor(bracelet) .navigationTransitionStyle( .zoom( sourceID: bracelet.id, in: braceletList ) ) } label: { BraceletPreview(bracelet) } .matchedTransitionSource( id: bracelet.id, in: braceletList ) However, I cannot get this animation. Expected (from WWDC video): Actual (iOS 18 simulator): How can I get the original animation?
1
0
507
Feb ’25
Set UILabel color in alertController
I have an alertController that is presented as popover on iPad let alertController = UIAlertController(title: alertTitle, message: alertMessage, preferredStyle: alertStyle) if let ppc = alertController.popoverPresentationController { // … } Is it possible to change the message font color (which is really very light on iPad) ? It is OK on iPhone with the same alert (not popover): text is much more readable:
1
0
365
Feb ’25
SwiftUI Transformable: support drag to Finder on macOS
I am trying to support dragging out a 'file' object from my app into Finder, on macOS. I have my object conform to Transferable and the files are saved on disk locally, so I just want to pass it the URL. This works fine when dragging out to other apps, like Notes or Mail, but not in Finder. I setup a ProxyRepresentation as well, as suggested by another thread, but it doesn't seem to help. Is there any other setup I need to do in the Xcode project file for it to work, or is there something else that I'm missing? @available(iOSApplicationExtension 17.0, macOSApplicationExtension 14.0, *) extension FileAttachments: Transferable { public static var transferRepresentation: some TransferRepresentation { FileRepresentation(exportedContentType: UTType.content) { content in SentTransferredFile(content.fullFileURL(), allowAccessingOriginalFile: false) } .exportingCondition { file in if let fileUTI = UTType(filenameExtension: file.fullFileURL().pathExtension), let fileURL = file.fullFileURL() { print("FileAttachments: FileRepresentation exportingCondition fileUTI: \(fileUTI) for file: \(fileURL)") return fileUTI.conforms(to: UTType.content) } return false } .suggestedFileName{$0.fileRenamedName} ProxyRepresentation { file in if let fileURL = file.fullFileURL() { print("FileAttachments: ProxyRepresentation returning file") return fileURL } return file.fullFileURL()! } } }
1
0
386
Feb ’25
SwiftUI navigationDestination will make child view's stateObject init multi times with sheet modifier.
Below is my sample code. On the Home page, when I click "show sheet," the sheet page expands, and the StateObject inside the sheet is initialized once. However, when I click "show Fullscreen" and then click "show sheet" inside the fullscreen page, the sheet gets initialized twice. However, if I remove navigationDestination, this issue does not occur. This problem causes the network request in the sheet page to be triggered multiple times. Can someone tell me the reason? enum TestRouter: String, Hashable { case test var targetView: some View { Text("test") } var title: String { return "test title" } } @MainActor struct NavigationInnerView<Content>: View where Content: View { var contentView: () -> Content @MainActor public init(@ViewBuilder contentView: @escaping () -> Content) { self.contentView = contentView } var body: some View { NavigationStack() { contentView() .navigationDestination(for: TestRouter.self) { route in route.targetView } } .navigationViewStyle(StackNavigationViewStyle()) } } struct ContentView: View { @State var showFullScreen: Bool = false @State var showSheet: Bool = false var contentView: some View { VStack { VStack { Text("Home") Button { showFullScreen = true } label: { Text("show fullscreen") } Button { showSheet = true } label: { Text("show sheet ") } } } } var body: some View { NavigationInnerView { contentView .fullScreenCover(isPresented: $showFullScreen) { NavigationInnerView { FullScreenContentView() } } .sheet(isPresented: $showSheet) { NavigationInnerView { SheetContentView() } } } } } class FullScreenViewModel: ObservableObject { @Published var content: Bool = false init() { print("Full Screen ViewModel init") } } struct FullScreenContentView: View { @Environment(\.dismiss) var dismiss @State var showSheet: Bool = false @StateObject var viewModel: FullScreenViewModel = .init() init() { print("Full screen view init") } var body: some View { VStack { Text("FullScreen") Button { dismiss() }label: { Text("dismiss") } Button { showSheet = true } label: { Text("show sheet") } } .sheet(isPresented: $showSheet) { NavigationInnerView { SheetContentView() } } } } class SheetViewModel: ObservableObject { @Published var content: Bool = false init() { print("SheetViewModel init") } } struct SheetContentView: View { @Environment(\.dismiss) var dismiss @StateObject var viewModel = SheetViewModel() init() { print("sheet view init") } var body: some View { Text("Sheet") Button { dismiss() } label: { Text("dismiss") } } } #Preview { ContentView() }
3
0
384
Feb ’25
Toolbar Display Bug When Using Zoom NavigationTransition with Swipe-Back Gesture
Could anyone help confirm if this is a bug and suggest possible solutions? Thanksssss In iOS 18, when using Zoom NavigationTransition, the toolbar from the destination view may randomly appear on the source view after navigating back with the swipe-back gesture. Re-entering the destination view and navigating back again can temporarily resolve the issue, but it may still occur intermittently. This bug only happens with Zoom NavigationTransition and does not occur when using a button tap to navigate back. import SwiftUI struct test: View { @Namespace private var namespace var body: some View { NavigationStack { NavigationLink { Image("img1") .resizable() .navigationTransition(.zoom(sourceID: 1, in: namespace)) .toolbar { ToolbarItem(placement: .bottomBar) { Text("destination noDisappear") } } } label: { Image("img1") .resizable() .frame(width: 100, height: 100) .matchedTransitionSource(id: 1, in: namespace) .toolbar { ToolbarItem(placement: .bottomBar) { Text("source toolbar") } } } } } }
1
0
288
Feb ’25
SwiftUI FocusState is not working in FocusCookbook sample project
I gave the FocusCookbook sample project a try and FocusState is not working correctly on iOS 18. I understand the sample was originally designed for iOS 17 when it was released along side the WWDC 2023 talk The SwiftUI Cookbook for Focus. however I am suprised it no longer works on iOS 18. E.g. when I launch the app on iPhone 16 Pro simulator (Xcode 16.2, iOS 18.2 Simulator) and tap the grocery list nav bar button, the grocery sheet appears however the last entry text field is not focused like .defaultFocus is designed to do. Futhermore, if I tap the add (+) button and a new entry is added, despite the addEmptyItem() func setting the currentItemID which is the @FocusState var the focus does not change to the new text field. Is FocusState broken on iOS 18? Relevant code from GroceryListView.swift import SwiftUI struct GroceryListView: View { @Environment(\.dismiss) private var dismiss @Binding var list: GroceryList @FocusState private var currentItemID: GroceryList.Item.ID? var body: some View { List($list.items) { $item in HStack { Toggle("Obtained", isOn: $item.isObtained) TextField("Item Name", text: $item.name) .onSubmit { addEmptyItem() } .focused($currentItemID, equals: item.id) } } .toolbar { ToolbarItem(placement: .cancellationAction) { doneButton } ToolbarItem(placement: .primaryAction) { newItemButton } } .defaultFocus($currentItemID, list.items.last?.id) } // MARK: New item private func addEmptyItem() { let newItem = list.addItem() currentItemID = newItem.id } private var newItemButton: some View { Button { addEmptyItem() } label: { Label("New Item", systemImage: "plus") } } private var doneButton: some View { Button { dismiss() } label: { Text("Done") } } }
Topic: UI Frameworks SubTopic: SwiftUI
2
0
458
Feb ’25