Provide views, controls, and layout structures for declaring your app's user interface using SwiftUI.

SwiftUI Documentation

Post

Replies

Boosts

Views

Activity

Get Video Thumbnail Image Asynchronously
public func getVideoThumbnailImage(url: URL) -> Image { let urlAsset = AVURLAsset(url: url, options: nil) let assetImageGenerator = AVAssetImageGenerator(asset: urlAsset) assetImageGenerator.appliesPreferredTrackTransform = true assetImageGenerator.apertureMode = .encodedPixels let cmTime = CMTime(seconds: 1, preferredTimescale: 60) var thumbnailCGImage: CGImage? var errorOccurred = false let semaphore = DispatchSemaphore(value: 0) assetImageGenerator.generateCGImageAsynchronously(for: cmTime) { generatedImage, timeGenerated, error in if error == nil { if let cgVideoImage = generatedImage { thumbnailCGImage = cgVideoImage } else { errorOccurred = true } } else { errorOccurred = true } semaphore.signal() return } _ = semaphore.wait(timeout: .now() + 30) if errorOccurred { return Image("ImageUnavailable") } if let thumbnailImage = thumbnailCGImage { let uiImage = UIImage(cgImage: thumbnailImage) return Image(uiImage: uiImage) } return Image("ImageUnavailable") } I am using Xcode 16 beta 2 for iOS 18 with SwiftUI. My code above works instantly and correctly; however, Xcode produces the purple warning: "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" How can I change the code to avoid the purple warning?
2
0
96
1w
Section Fully Clickable in SwiftUI – NavigationLink Issue
Hi everyone, I’m having an issue with SwiftUI where my entire Section becomes clickable, instead of just the “Edit profile” button. Here’s my code: VStack(alignment: .center) { KFImage(authManager.user?.photoURL) .resizable() .scaledToFill() .frame(width: 80, height: 80) .clipShape(Circle()) Text(authManager.user?.displayName ?? "") .font(.system(.title, design: .rounded)) Text(authManager.user?.email ?? "") .font(.subheadline) .foregroundColor(.gray) NavigationLink { EditProfileView() } label: { Text("Edit profile") .frame(minWidth: 0, maxWidth: .infinity) .font(.system(size: 18)) .padding(10) .foregroundColor(.white) .background(Color.blue) .cornerRadius(25) } .padding(.top, 5) } .frame(maxWidth: .infinity, alignment: .center) } I want only the button to be clickable. How can I fix this? Thanks! Link to issue: https://imgur.com/a/iO9aNSM
1
0
119
1w
SwiftUI Previews not working with Firebase in Xcode 16.0 beta
The SwiftUI previews have been working fine in Xcode 16.0 beta, but ever since I added Firebase into my app, I've been getting error with previews. CrashReportError: IshaanCord crashed IshaanCord crashed. Check ~/Library/Logs/DiagnosticReports for crash logs from your application. Process: IshaanCord[5651] Date/Time: 2024-07-04 19:29:51 +0000 Log File: <none> "Cannot preview in this file" Does anyone know how to fix this? Thank you.
2
0
231
1w
How to replace tabBar with bottomBar with smooth animation in SwiftUI?
I am trying to replace the navigation tab bar with a custom bottom toolbar when a view enters edit mode. Currently, I am using the following code to achieve this: content .toolbar(isEditing ? .hidden : .visible, for: .tabBar) . toolbar(isEditing ? .visible : .hidden, for: .bottomBar) However, this results in a janky animation. When the bottom bar appears, it animates in above (in contrast to in place of) the tab bar, then "jumps" back down to the correct offset without animation. I had to workaround this by delaying the appearance of bottom bar by 0.3s. I am already using withAnimation(). Is this a bug or am I using the APIs incorrectly? Is there a more seamless way to achieve this switching effect other than delaying the bottom bar? Thanks!
1
0
131
1w
SwiftUI Previews broken on local Swift Package with dependencies
I have a project with two local packages One client package with an interface and some models with dynamic type in the Package.Swift One feature package with the UI and a dependency to the client package When I try to preview a view that is not using any models or code from the client package, it loads just fine e.g. a view that is just a container to display things like a card But when I tried to preview any other view that actually uses models from the client package, it just fails the first few lines of the preview error display LinkDylibError: Failed to build <filename>.swift Linking failed: linker command failed with exit code 1 (use -v to see invocation) ld: warning: search path '/Applications/Xcode-15.4.0.app/Contents/SharedFrameworks-iphonesimulator' not found Undefined symbols for architecture arm64: Also, I'm using Xcode 15.4 and iOS 17 as the min version
2
1
209
4w
WKExtensionsDelegateClassName is Invalid in info.plist
So I am banging my head, I realized my stand along Watch App had a STUPID long name of "App Name - WatchKit App" so I went into my Target and changed the Display Name to "App Name" removing WatchKit App. Well now my app won't validate when uploading to the Appstore. I get the message - Invalid Info.plist key. The key WKExtensionDelegateClassName in bundle App Name.app/Watch/App Name WatchKit App.app is invalid.  My Info.plist has the value of <key>WKExtensionDelegateClassName</key> <string>$(PRODUCT_MODULE_NAME).ExtensionDelegate</string> I have confirmed that I have  @WKExtensionDelegateAdaptor(ExtensionDelegate.self) var delegate in my @main for the SwiftUI App. And when I print a few values in my app launch I get the following confirmations: Super Init - ExtensionDelegate Contentview applicationDidFinishLaunching for watchOS Super Init - ExtensionDelegate Optional(My_App_Extension.Setup) Optional(My_App_Extension.Statistics) Optional(My_App_Extension.Other) applicationDidBecomeActive for watchOS update complication I create three classes at launch and print this in the log with print(ExtensionDelegate.shared.Setup as Any) , etc. The other lines are just confirming where I am at app startup. This is a WatchOS8 application and I am running Xcode version Version 13.1 (13A1030d).
2
1
936
Nov ’21
NavigationSplitView freezes
DESCRIPTION OF PROBLEM I have changed my app to the @Observable-Macro. When using an iPhone (on simulator and on real device) the navigation from a player to the player detail view and back breaks. In the attached video on my GitHub you can see me tapping on both players in the team, but the navigation ist not showing the detail view. What is the reason? Is my usage/understanding of @Observable wrong? Is it wrong to have the selectedPlayer within the PlayerController which is @Observable? And why does it sometimes work and sometimes not? The project can be found here: GitHub Project STEPS TO REPRODUCE Start the App, add one or two demo teams, tap on a team and add two or more demo players. tap a player and then go back, tap the player again and back again. After a while (number of taps is always different), the navigation breaks. See my video attached. PLATFORM AND VERSION iOS Development environment: Xcode 15.4, macOS 14.5 (23F79) Run-time configuration: iOS 17.5,
0
0
89
1w
Confusing SwiftUI error log: "Mutating observable property after view is torn down has no effect"
Hey, I have a setup in my app that I am currently building, that uses @Observable router objects that hold the app's entire navigation state, so that I can easily set it globally and let SwiftUI show the appropriate views accordingly. Each view gets passed in such a router object and there is a global "app" router that the app's root view can access as an entry point: @Observable @MainActor final class AppRouter { static let shared = AppRouter() // Entry point used by the app's root view var isShowingSheet = false // Navigation state let sheetRouter = SheetRouter() // Router that's passed to the sheet view. This router could contain other routers for sheets it will show, and so on } @Observable @MainActor final class SheetRouter { // Example of a "nested" router for a sheet view var path = NavigationPath() var isShowingOtherSheet = false func reset() { path = .init() isShowingOtherSheet = false } } To open a sheet, I have a button like this: @Bindable var appRouter = AppRouter.shared // ... Button("Present") { appRouter.sheetRouter.reset() // Reset sheet router appRouter.isShowingSheet = true // show sheet } This seems to work perfectly fine. However, this produces tons of "error" logs in the console, whenever I open the sheet for a second time: Mutating observable property \SheetRouter.path after view is torn down has no effect. Mutating observable property \SheetRouter.path after view is torn down has no effect. Mutating observable property \SheetRouter.path after view is torn down has no effect. Mutating observable property \SheetRouter.path after view is torn down has no effect. Mutating observable property \SheetRouter.isShowingOtherSheet after view is torn down has no effect. These errors appear when calling the reset() of the sheet view's router before opening the sheet. That method simply resets all navigation states in a router back to their defaults. It's as if the sheetRouter is still connected to the dismissed view from the previous sheet, causing a mutation to trigger these error logs. Am I misusing SwiftUI here or is that a bug? It's also worth mentioning that these error logs do not appear on iOS 17. Only on iOS 18. So it might be a bug but I just want to make sure my usage of these router objects is okay and not a misuse of the SwiftUI API that the runtime previously simply did not catch/notice. Then I'd have to rewrite my entire navigation logic. I do have an example project to demonstrate the issue. You can find it here: https://github.com/SwiftedMind/PresentationBugDemo. I have also filed a feedback for this: FB14162780 STEPS TO REPRODUCE Open the example project. Open the sheet in the ContentView twice by tapping "Present" Close that sheet Open it again. Then the console will show these error logs from above. I'd appreciate any help with this. Cheers
2
2
253
1w
Online data to swift UI
Hello! I have been working on an app for quite some time now, and one of my views is of a bunch of different articles that my brand has written. The articles can be found on their website, and so as of late, I have just been copying and pasting all of the data from each article into a JSON file in my app; However, as the list of articles grow, I need to fetch the data directly from the website and have it integrated with my code, so every time a new article is published, users dont have to update their app. Is there any way someone could help with this? I've been struggling for a while now. Thanks!
2
0
149
1w
ViewDidLoad in SwiftUI
Hello. I want to do a fetch when a view loads. In UIKit I would have used viewDidLoad to do this but in SwiftUI we only have onAppear and task. Is that by design, and if so, what is the recommended way to fetch data? I wrote a little blog post for a workaround describing the issue and the found solution, but I presume there is a better way. https://www.ludafux.com/post/viewdidload_doppelganger Best Regards, Luda
4
0
137
1w
UIUserInterfaceIdiom Errors
Hello, I am getting following errors in Xcode console when running my app on the simulator with iPad Pro 13-inch (M4) 17.4: CoreUI: _Bool CUIValidateIdiomSubtypes(NSInteger, NSUInteger *) passed a device subtype '2752' and idiom '2':pad that are not a matching pair, subtype is not valid with given idiom. Assuming subtype should be 0 instead. This is the code: import Foundation import SwiftUI struct PrefersTabNavigationEnvironmentKey: EnvironmentKey { static var defaultValue: Bool = false } extension EnvironmentValues { var prefersTabNavigation: Bool { get { self[PrefersTabNavigationEnvironmentKey.self] } set { self[PrefersTabNavigationEnvironmentKey.self] = newValue } } } #if os(iOS) extension PrefersTabNavigationEnvironmentKey: UITraitBridgedEnvironmentKey { static func read(from traitCollection: UITraitCollection) -> Bool { return traitCollection.userInterfaceIdiom == .phone || traitCollection.userInterfaceIdiom == .pad || traitCollection.userInterfaceIdiom == .tv } static func write(to mutableTraits: inout UIMutableTraits, value: Bool) { // do not write } } #endif I am using this to decide what layout of the app to use – learned this from the Apple sample app Backyards Birds: if prefersTabNavigation { AppTabView(selection: $selection) } else { NavigationSplitView { AppSideBar(selection: $selection) } detail: { AppDetailColumn(screen: selection) } } Could you please help me find out what is wrong with the code?
2
0
95
1w
Interactive Live Activity in watchOS 11 - not getting AppIntent buttons to work
I have started to work on adding Live Activities to my app in watchOS 11. The app already has interactive Live Activities on the phone that works as expected. I have added a view for the activityFamily: small and it shows up as expected. My problem is that buttons doesn't work. I use the Intent based button, and on the iPhone Lock Screen they work. On the watch, nothing happens. Has anyone got this working? Not sure if I'm missing something or if it's a bug.
3
0
270
4w
Problem with NavigationLink
I am making application where I use navigation link to navigate from bottom menu to other views, and there is a problem when I change view a few times because views start stacking and when I set navigationBarBackButtonHidden(false) I can see on left side a lot of back button. This generate big problem because after changing views I got warning Abnormal number of gesture recognizer dependencies: 100. System performance may be affected. Please investigate reducing gesture recognizers and/or their dependencies. And after some more changes everything from screen is pushed down back button. Is there any solution to close previous view from we came? There is code: // // BottomMenu.swift // SpaceManager // // Created by Kuba Kromomołowski on 04/05/2024. // import SwiftUI import Firebase import FirebaseAuth struct BottomMenu: View { @StateObject var logManager = MainViewModel() @StateObject var mvm = MenuViewModel() @State var condition1: Bool = true @State var condition2: Bool = false @State var condition3: Bool = false // @StateObject private var cameraViewModel = CameraViewModel() var body: some View { HStack{ Group{ //.navigationBarBackButtonHidden(true) Spacer() BtnMenu(btnText: "Dodaj", btnIcon: "plus.app.fill", destinationView:AnyView(LoggedMainView()), isActive: condition1 ) Spacer() BtnMenu(btnText: "Szukaj", btnIcon: "magnifyingglass", destinationView:AnyView(SearchView()), isActive: condition2 ) Spacer() BtnMenu(btnText: "Profil", btnIcon: "person.crop.circle.fill", destinationView:AnyView(ProfileView()), isActive: condition3 ) Spacer() }.padding(.bottom, 30) .font(.system(size: 20)) } } } #Preview { BottomMenu() } // // BtnMenu.swift // SpaceManager // // Created by Kuba Kromomołowski on 04/05/2024. // import SwiftUI struct BtnMenu: View { var btnText: String var btnIcon: String var destinationView: AnyView @State var isActive: Bool = true var body: some View { NavigationLink{ destinationView } label: { ZStack { Text("\(Image(systemName: btnIcon)) \(btnText)") } }.disabled(isActive) } }
1
0
116
1w
Need some help! Failed to produce diagnostic for expression error
Hey y'all, im semi new to the coding world and have just come across this error: Failed to produce diagnostic for expression; please submit a bug report (https://swift.org/contributing/#reporting-bugs) ive been building for a little while and can't figure out why. Ive rebuilt and tried everything. Any help would be appreciated! This is the code: import SwiftUI import Combine struct LoginView: View { @EnvironmentObject var authManager: AuthenticationManager @State private var email = "" @State private var password = "" @State private var showingAlert = false @State private var alertMessage = "" @State private var keyboardHeight: CGFloat = 0 var body: some View { GeometryReader { geometry in NavigationView { ZStack { LinearGradient(gradient: Gradient(colors: [Color.red, Color.black]), startPoint: .top, endPoint: .bottom) .edgesIgnoringSafeArea(.all) VStack { Image("GottaDraftEmAll") .resizable() .scaledToFit() .frame(width: geometry.size.width * 0.8, height: geometry.size.height * 0.1) .padding(.top, 25) Spacer() Image("pokeball") .resizable() .scaledToFit() .frame(width: geometry.size.width * 0.6, height: geometry.size.width * 0.6) .padding(.bottom, 20) VStack(spacing: 15) { TextField("", text: $email) .padding() .background(Color.white.opacity(0.8)) .cornerRadius(10) .padding(.horizontal, 20) .foregroundColor(.black) .overlay( HStack { Text(email.isEmpty ? "Email" : "") .foregroundColor(Color.black.opacity(0.7)) .padding(.leading, 25) Spacer() } ) SecureField("", text: $password) .padding() .background(Color.white.opacity(0.8)) .cornerRadius(10) .padding(.horizontal, 20) .foregroundColor(.black) .overlay( HStack { Text(password.isEmpty ? "Password" : "") .foregroundColor(Color.black.opacity(0.7)) .padding(.leading, 25) Spacer() } ) } .padding(.top, 50) Button(action: { authManager.signIn(email: email, password: password) { success, error in if !success { alertMessage = error ?? "An unknown error occurred" showingAlert = true } } }) { Text("LOGIN") .font(.headline) .foregroundColor(.white) .padding() .frame(maxWidth: .infinity) } .buttonStyle(GlowGradientButtonStyle()) .padding(.horizontal, 20) .padding(.top, 20) NavigationLink(destination: SignUpView()) { Text("Don't have an account? Sign Up") .foregroundColor(.white) } .padding(.top, 10) Spacer() } .padding(.bottom, keyboardHeight) } .onAppear { NotificationCenter.default.addObserver(forName: UIResponder.keyboardWillShowNotification, object: nil, queue: .main) { notification in if let value = notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? CGRect { self.keyboardHeight = value.height } } NotificationCenter.default.addObserver(forName: UIResponder.keyboardWillHideNotification, object: nil, queue: .main) { _ in self.keyboardHeight = 0 } } .onDisappear { NotificationCenter.default.removeObserver(self, name: UIResponder.keyboardWillShowNotification, object: nil) NotificationCenter.default.removeObserver(self, name: UIResponder.keyboardWillHideNotification, object: nil) } .alert(isPresented: $showingAlert) { Alert(title: Text("Login Error"), message: Text(alertMessage), dismissButton: .default(Text("OK"))) } } } } }
1
0
132
1w
Xcode 16 Beta, macOS 15 Beta - Lists look different?!
Hi, I was testing my project running on macOS 15 Beta and Xcode 16 Beta and noticed that lists look slightly different. They generally look somewhat smaller, like the font size or spacing is now different. It's kinda hard to describe so I made screenshots depicting what the list looks like on macOS 14 + Xcode 15 and macOS 15 Beta + Xcode 16 Beta to show what I mean. Did you experience similar issues?
1
0
167
1w
Is it Possible to save AttributedString with image to RTF doc?
Hello, I am trying to implement an RTF document export feature on a small app. But after days of trying and failing with dozens of approaches I’m beginning to wonder if it is even possible to create an .rtf file with embedded text and images in Swift/SwiftUI. I’ve tried many variations of (A) building the text and image content with HTML, converting it to AttributedString, then exporting to RTF, and (B) building the text and image content directly with AttributedString attributes and attachments for the image — and in both cases, the images are not saved in the RTF file. I am able to create a preview of the AttributedString with formatted text and image, and able to create an RTF file with formatted text that opens with TextEdit, Pages and Word without issue; but cannot get the image to appear in the saved RTF file. I’m hoping someone here can shed some light on if this is possible and if yes, how to save the combined text and image data to an RTF file. Here is the latest variation of the code I’m using — any ideas/suggestions are appreciated 🙏🏽: import SwiftUI struct ContentView: View { @State private var showExportSheet = false @State private var rtfData: Data? @State private var isLoading = false @State private var previewAttributedString: NSAttributedString? var body: some View { VStack { Button("Export RTF with Image") { isLoading = true createRTFWithEmbeddedImage() } .disabled(isLoading) if isLoading { ProgressView() } if let previewAttributedString = previewAttributedString { VStack { Text("Preview:") .font(.headline) TextView(attributedString: previewAttributedString) .frame(minWidth: 0, maxWidth: .infinity, minHeight: 200, maxHeight: .infinity) .background(Color.gray.opacity(0.1)) } .padding() } } .sheet(isPresented: $showExportSheet) { DocumentPicker(rtfData: $rtfData) } } func createRTFWithEmbeddedImage() { let text = "This is a sample RTF document with an embedded image:" // Load the image (star.fill as a fallback) guard let image = UIImage(systemName: "star.fill") else { print("Failed to load image") isLoading = false return } // Resize the image to 100x100 pixels let resizedImage = resizeImage(image: image, targetSize: CGSize(width: 100, height: 100)) // Convert image to NSTextAttachment let attachment = NSTextAttachment() attachment.image = resizedImage // Set bounds for the image attachment.bounds = CGRect(x: 0, y: 0, width: 100, height: 100) // Create attributed string with the attachment let attributedString = NSMutableAttributedString(string: text) let attachmentString = NSAttributedString(attachment: attachment) attributedString.append(attachmentString) // Add red border around the image attributedString.addAttribute(.strokeColor, value: UIColor.red, range: NSRange(location: attributedString.length - attachmentString.length, length: attachmentString.length)) attributedString.addAttribute(.strokeWidth, value: -2.0, range: NSRange(location: attributedString.length - attachmentString.length, length: attachmentString.length)) // Set previewAttributedString for preview self.previewAttributedString = attributedString // Convert attributed string to RTF data guard let rtfData = try? attributedString.data(from: NSRange(location: 0, length: attributedString.length), documentAttributes: [.documentType: NSAttributedString.DocumentType.rtf]) else { print("Failed to create RTF data") isLoading = false return } self.rtfData = rtfData isLoading = false showExportSheet = true // Debug: Save RTF to a file in the Documents directory saveRTFToDocuments(rtfData) } func resizeImage(image: UIImage, targetSize: CGSize) -> UIImage { let size = image.size let widthRatio = targetSize.width / size.width let heightRatio = targetSize.height / size.height let newSize: CGSize if widthRatio > heightRatio { newSize = CGSize(width: size.width * heightRatio, height: size.height * heightRatio) } else { newSize = CGSize(width: size.width * widthRatio, height: size.height * widthRatio) } let rect = CGRect(origin: .zero, size: newSize) UIGraphicsBeginImageContextWithOptions(newSize, false, 1.0) image.draw(in: rect) let newImage = UIGraphicsGetImageFromCurrentImageContext() UIGraphicsEndImageContext() return newImage ?? UIImage() } func saveRTFToDocuments(_ data: Data) { let fileManager = FileManager.default guard let documentsDirectory = fileManager.urls(for: .documentDirectory, in: .userDomainMask).first else { print("Unable to access Documents directory") return } let fileURL = documentsDirectory.appendingPathComponent("debug_output.rtf") do { try data.write(to: fileURL) print("Debug RTF file saved to: \(fileURL.path)") } catch { print("Error saving debug RTF file: \(error)") } } } struct DocumentPicker: UIViewControllerRepresentable { @Binding var rtfData: Data? func makeUIViewController(context: Context) -> UIDocumentPickerViewController { let tempURL = FileManager.default.temporaryDirectory.appendingPathComponent("document_with_image.rtf") do { try rtfData?.write(to: tempURL) } catch { print("Error writing RTF file: \(error)") } let picker = UIDocumentPickerViewController(forExporting: [tempURL], asCopy: true) return picker } func updateUIViewController(_ uiViewController: UIDocumentPickerViewController, context: Context) {} } struct TextView: UIViewRepresentable { let attributedString: NSAttributedString func makeUIView(context: Context) -> UITextView { let textView = UITextView() textView.isEditable = false textView.attributedText = attributedString return textView } func updateUIView(_ uiView: UITextView, context: Context) { uiView.attributedText = attributedString } } Thank in advance!
2
0
156
1w