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

SwiftUI Documentation

Post

Replies

Boosts

Views

Activity

Pop to root view when selected tab is tapped again for WebKit
Hello everyone! I have a WKWebView in my swiftui app and would like to enable to "pop root view when selected tab is tapped again" feature, but I have been unable to figure out how to implement this. Here's the basic code: class TabIdentifierModel:ObservableObject { @Published var tabSelection:TabIdentifier { willSet { if newValue == tabSelection { NotificationCenter.default.post(name: .popRootView, object: nil, userInfo: ["tab": newValue.rawValue]) } } } init() { tabSelection = .home } } struct ContentView: View { @AppStorage(AppStorageKeys.enableShorts) var enableShorts = true @StateObject var storeVM = StoreVM() @StateObject var downloadURLManager = DownloadURLManager.shared @State var downloadViewIsOpen = false // ...... @State var tabSelection = TabIdentifierModel() var body: some View { TabView(selection: $tabSelection.tabSelection) { // ...... WebViewWrapper(url: $libraryTabURL) .tabItem { Label { Text("Library") } icon: { Image(systemName: "folder.fill") } }.tag(TabIdentifier.library) // ...... } .environmentObject(tabSelection) } } Tapping on the tab again doesn't seem to set the value again thus the NotificationCenter.default.post is not sent and the web view is not reloaded. Help would be much appreciated! Thanks in advance!
0
0
150
3w
SwiftUI pushWindow debug
In my case, I open an immersiveSpace and windowGroupA together. When I successfully push a new windowGroupB from windowGroupA, dismissing windowGroupB should return me to windowGroupA. However, this fails, and windowGroupA remains in the background scenePhase. I tried closing immersiveSpace, and it worked successfully. Therefore, pushWindow cannot be used when immersiveSpace is open.
1
0
177
3w
State restoration in Document-based iOS app
Greetings - If I build an app using DocumentGroup, I get the document picker when the app launches. A good iOS app should restore the state the app was in when it was closed. It seems like with DocumentGroup, when the user leaves my app and the app is killed, the next time they launch it, they have to remember the document they were working on and reopen it. How can I have my DocumentGroup-based app restore the last open document at launch? FB13874563 Thanks - Steve
0
0
109
3w
Location Permission Popup Not Appearing in SwiftUI App
Hello everyone, I'm working on a SwiftUI app that requires location services, and I've implemented a LocationManager class to handle location updates and permissions. However, I'm facing an issue where the location permission popup does not appear when the app is launched. Here is my current implementation: LocationManager.swift: import CoreLocation import SwiftUI class LocationManager: NSObject, ObservableObject, CLLocationManagerDelegate { private let locationManager = CLLocationManager() @Published var userLocation: CLLocation? @Published var isAuthorized = false @Published var authorizationStatus: CLAuthorizationStatus = .notDetermined override init() { super.init() locationManager.delegate = self checkAuthorizationStatus() } func startLocationUpdates() { locationManager.startUpdatingLocation() } func stopLocationUpdates() { locationManager.stopUpdatingLocation() } func requestLocationAuthorization() { print("Requesting location authorization") DispatchQueue.main.async { self.locationManager.requestWhenInUseAuthorization() } } private func checkAuthorizationStatus() { print("Checking authorization status") authorizationStatus = locationManager.authorizationStatus print("Initial authorization status: \(authorizationStatus.rawValue)") handleAuthorizationStatus(authorizationStatus) } func locationManagerDidChangeAuthorization(_ manager: CLLocationManager) { print("Authorization status changed") authorizationStatus = manager.authorizationStatus print("New authorization status: \(authorizationStatus.rawValue)") handleAuthorizationStatus(authorizationStatus) } private func handleAuthorizationStatus(_ status: CLAuthorizationStatus) { switch status { case .authorizedAlways, .authorizedWhenInUse: DispatchQueue.main.async { self.isAuthorized = true self.startLocationUpdates() } case .notDetermined: requestLocationAuthorization() case .denied, .restricted: DispatchQueue.main.async { self.isAuthorized = false self.stopLocationUpdates() print("Location access denied or restricted") } @unknown default: DispatchQueue.main.async { self.isAuthorized = false self.stopLocationUpdates() } } } func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) { DispatchQueue.main.async { self.userLocation = locations.last } } func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) { print("Location manager error: \(error.localizedDescription)") } } MapzinApp.swift: @main struct MapzinApp: App { @UIApplicationDelegateAdaptor(AppDelegate.self) var delegate @StateObject private var locationManager = LocationManager() var body: some Scene { WindowGroup { Group { if locationManager.authorizationStatus == .notDetermined { Text("Determining location authorization status...") } else if locationManager.isAuthorized { CoordinatorView() .environmentObject(locationManager) } else { Text("Location access is required to use this app. Please enable it in Settings.") } } } } } Log input: Checking authorization status Initial authorization status: 0 Requesting location authorization Authorization status changed New authorization status: 0 Requesting location authorization Despite calling requestWhenInUseAuthorization() when the authorization status is .notDetermined, the permission popup never appears. Here are the specific steps I have taken: Checked the Info.plist to ensure the necessary keys for location usage are present: NSLocationWhenInUseUsageDescription NSLocationAlwaysUsageDescription NSLocationAlwaysAndWhenInUseUsageDescription Verified that the app's target settings include location services capabilities. Tested on a real device to ensure it's not a simulator issue. I'm not sure what I might be missing. Any advice or suggestions to resolve this issue would be greatly appreciated. Thank you!
1
0
248
3w
Handling of dates with no value when creating a date bar chart in Charts
Some data have skipped dates, as in the following data. TrainingSession(date: formatter.date(from: "2024-05-12 07:37:30 +0000")!, maxRM: 10.0, totalVolume: 0.0), TrainingSession(date: formatter.date(from: "2024-06-01 15:00:00 +0000")!, maxRM: 10.5, totalVolume: 105.0), TrainingSession(date: formatter.date(from: "2024-06-03 15:00:00 +0000")!, maxRM: 10.0, totalVolume: 100.0) In this case, the graph shows nothing for the corresponding date as shown in the image. s it possible to create a continuous graph by displaying only the data with values and not the dates with no values? The source code is as follows // ContentView.swift // GraphSample // // Created by 齋藤卓馬 on 2024/06/09. // import SwiftUI import Charts struct TrainingSession { var date: Date var maxRM: Double var totalVolume: Double } struct GraphView: View { var sessions: [TrainingSession] var body: some View { ScrollView { VStack(alignment: .leading) { // 最大RMのグラフ VStack(alignment: .leading) { Text("最大RM") .font(.headline) .padding() Chart(sessions, id: \.date) { session in BarMark( x: .value("Date", session.date), y: .value("Max RM", session.maxRM) ) } .chartXAxis { AxisMarks(values: .stride(by: .day, count:7)) // 日付の表示間隔を調整 } .chartScrollableAxes(.horizontal) // 横スクロールを有効にする .padding([.leading, .trailing, .bottom]) } // 総負荷量のグラフ VStack(alignment: .leading) { Text("総負荷量") .font(.headline) .padding() Chart(sessions, id: \.date) { session in BarMark( x: .value("Date", session.date), y: .value("Total Volume", session.totalVolume) ) } .chartXAxis { AxisMarks(values: .stride(by: .day, count:7)) // 日付の表示間隔を調整 } .chartScrollableAxes(.horizontal) // 横スクロールを有効にする .padding([.leading, .trailing, .bottom]) } } } } } struct ContentView: View { var body: some View { GraphView(sessions: sampleData) } var sampleData: [TrainingSession] { let formatter = DateFormatter() formatter.dateFormat = "yyyy-MM-dd HH:mm:ss Z" return [ TrainingSession(date: formatter.date(from: "2024-05-12 07:37:30 +0000")!, maxRM: 10.0, totalVolume: 0.0), TrainingSession(date: formatter.date(from: "2024-06-01 15:00:00 +0000")!, maxRM: 10.5, totalVolume: 105.0), TrainingSession(date: formatter.date(from: "2024-06-03 15:00:00 +0000")!, maxRM: 10.0, totalVolume: 100.0) ] } } struct MyApp: App { var body: some Scene { WindowGroup { ContentView() } } }
2
0
239
Jun ’24
Creating a navigation link within a chart?
I’d like to create a simple Gantt chart where each horizontal BarMark is a navigation link to a detail view. When I embed a navigation link within a chart, I get the error “Static method 'buildExpression' requires that 'some ChartContent' conform to 'View’” NavigationLink(value: taskGroup) { BarMark( xStart: .value("Start", taskGroup.start), xEnd: .value("End", taskGroup.end), y: .value("Event", taskGroup.taskGroupName), height: barHeight ) } I could use a chart overlay and manage the navigation from there, but it appears I can only grab published chart data at a given tap gesture. I need the object itself to inject into the detail view (in this case TaskGroup) and the data I’m plotting in the chart isn’t unique - so no obvious way to identify which TaskGroup the user tapped.
3
0
316
Jun ’24
How can Charts display sales data for a full month and support monthly paging?
Due to the varying number of days in each month, I am unsure how to enable monthly paging in Charts. In Apple's official example, SwiftChartsExample, there is only an example showing the sales of the "last 30 days": .chartXVisibleDomain(length: 3600 * 24 * 30) I have tried using scrollPosition to calculate the number of days in the current month, like this: var days: Int { let current = Calendar.current let dateRange = current.range(of: .day, in: .month, for: scrollPosition) return dateRange?.count ?? 0 } ... .chartXVisibleDomain(length: 3600 * 24 * days) ... .chartScrollPosition(x: $scrollPosition) ... But I found that it does not work as expected. 😢
2
0
270
May ’24
SwiftUI chart - take screenshot of the chart view on macOS
Hello all, if I enable the .chartScrollableAxes(.horizontal) and .chartXVisibleDomain(length: length) for a chart view to zoom in the screenshot of the view misses the graphs. I use this extension: `extension View { @MainActor func snapshot() { let renderer = ImageRenderer(content: self) if let exportImage = renderer.nsImage { let pasteboard = NSPasteboard.general pasteboard.clearContents() pasteboard.writeObjects([exportImage]) } } }` The screenshot is taken with: Button("Snap") { let view = ChartView(text: $statusText, length: $chartLength) .padding() .frame(width: 1500, height: 500) view.snapshot() } If I omit .chartScrollableAxes(.horizontal) the snapshot is ok and the graphs are visible in the image but then a zoom is not possible and the whole range is shown. Any ideas?
1
1
306
Apr ’24
quickLookPreview keyboard issues on macOS
I'm trying to add QuickLook previews to a SwiftUI app which uses Table(). I've added the .quickLookPreview() modifier to my Table(), and added a menu command for invoking it, and if I select that menu item manually, it works fine, but I have two keyboard related issues which are making it difficult to actually ship this functionality: When using the .quickLookPreview() variant for a set of URLs, keyboard navigation between the quicklook previews only works with left/right arrows, but being invoked by a Table, it would make much more sense for up/down arrows to navigate through the previews I set a .keyboardShortcut() on the menu command to use Space, since that's the normally-expected shortcut for quicklook, and it doesn't work. If I set it to some random other key (like "a") it does work, but .space doesn't do anything.
2
0
133
3w
Deep Link to Files app
Is there a system deep link URI to the built in files app? I would like to direct users to my apps location in the files app. For example files://myApp The only exposed deep links for system I can find are the ones for mail, sms, FaceTime etc. Thank you (tag used for post was because I couldn’t find a deep link tag)
3
0
338
May ’24
Long Hang Times When Accessing View With Posts
For some reason, every time I'm accessing a view populated with posts and fetching posts, my app has like a 5-8 second hang time. I don't know whats causing this issue, and I have been dealing with this for 3 days. `func fetchPosts(completion: @escaping (Result<[PostWithUser], Error>) -> Void) { if !cachedPosts.isEmpty { completion(.success(self.cachedPosts)) return } postsRef.order(by: "timestamp", descending: true).getDocuments { [weak self] snapshot, error in guard let self = self else { return } if let error = error { completion(.failure(error)) return } guard let documents = snapshot?.documents else { completion(.success([])) return } let group = DispatchGroup() var postsWithUsers: [PostWithUser] = [] DispatchQueue.global(qos: .userInitiated).async { for document in documents { group.enter() let data = document.data() guard let userId = data["userId"] as? String, let parentId = data["parentId"] as? String, let groupId = data["groupId"] as? String, let text = data["text"] as? String, let isPinned = data["isPinned"] as? Bool, let imageUrl = data["imageUrl"] as? String, let videoUrl = data["videoUrl"] as? String, let timestamp = data["timestamp"] as? Timestamp, let views = data["views"] as? Int else { group.leave() continue } let post = Post(id: document.documentID, userId: userId, parentId: parentId, groupId: groupId, text: text, imageUrl: imageUrl, videoUrl: videoUrl, timestamp: timestamp.dateValue(), isPinned: isPinned, likedBy: [], views: views) self.usersRef.document(userId).getDocument { userDocument, error in defer { group.leave() } if let userDocument = userDocument, let userData = userDocument.data() { let user = User( id: userId, username: userData["username"] as? String ?? "", bio: userData["bio"] as? String ?? "", profilePictureUrl: userData["profileImageUrl"] as? String ?? "", privateProfile: userData["privateProfile"] as? Bool ?? false, privateFollowerList: userData["privateFollowerList"] as? Bool ?? false, privateFollowingList: userData["privateFollowingList"] as? Bool ?? false, privateReplies: userData["privateReplies"] as? Bool ?? false, privateLikes: userData["privateLikes"] as? Bool ?? false ) let postWithUser = PostWithUser(post: post, user: user) DispatchQueue.main.async { postsWithUsers.append(postWithUser) } } else { print("Failed to fetch user data for userId: \(userId), error: \(String(describing: error))") } } } group.notify(queue: .main) { self.cachedPosts = postsWithUsers completion(.success(postsWithUsers)) } } } }` ` func fetchPosts() { PostService.shared.fetchPosts { result in switch result { case .success(let posts): DispatchQueue.main.async { self.posts = posts } case .failure(let error): print("Failed to fetch posts: \(error)") } } } func refreshPosts() { PostService.shared.refreshPosts { result in switch result { case .success(let posts): DispatchQueue.main.async { self.posts = posts } case .failure(let error): print("Failed to fetch posts: \(error)") } } }
1
0
164
3w
scrollPosition(id:anchor:) freeze UI when show/hide keyboard
Hello ! This will be my first blog post. I hope I will find the solution. So, I try to use the new iOS 17+ API for ScrollView. I have an array of messages that I want to show in scroll view. And I need to scroll to bottom when I tap to Send button. When I use scrollPosition(id:anchor:), it freeze the UI. The link to the screencast to demonstrate. I think the problem might be the keyboard when it shows and hides. But I can't understand what can I do. struct ChatView: View { @ObservedObject var viewModel: CoachViewModel @State private var scrollTo: Message.ID? var body: some View { ScrollView { LazyVStack { ForEach(viewModel.messages) { message in MessageView(viewModel: viewModel, message: message) } } .scrollTargetLayout() } .scrollPosition(id: $scrollTo) .background(.primaryBackground) .onChange(of: viewModel.scrollToBottom) { if $1, let lastMessage = viewModel.messages.last { withAnimation { scrollTo = lastMessage.id } viewModel.scrollToBottom = false } } } } struct Message: Identifiable, Hashable { let id: UUID let author: MessageAuthor let text: String } final class CoachViewModel: ObservableObject { @Published var messageTextInput = "" @Published var scrollToBottom = false @Published var messages: [Message] = [...] // ... more code ... func sendMessage() { messages.append( .init( id: .init(), author: .user, text: messageTextInput ) ) messageTextInput.removeAll() scrollToBottom = true } } struct CoachView: View { @StateObject private var viewModel = CoachViewModel() @State private var isSearching = false var body: some View { VStack(spacing: 0) { Group { CoachTitleView(viewModel: viewModel, isSearching: $isSearching) ChatView(viewModel: viewModel) } .onTapGesture { UIApplication.shared.endEditing() } if isSearching { MatchboxView(viewModel: viewModel) } else { InputTextFieldView(viewModel: viewModel) } } } }
0
0
150
3w
Questions Tags Saves Users Companies LABS Jobs Discussions COLLECTIVES Communities for your favorite technologies. Explore all Collectives TEAMS Ask questions, find answers and collaborate at work with Stack Overflow for Teams. Looking for your
0 I'm trying to make a list of trips that a person has gone on, and when someone has no trips in their list, it will display a ContentUnavailableView with a NavigationLink to take them to a new view. I am encountering strange issues when using the ContentUnavailableView with the NavigationLink, such as the back button being unaligned and not being able to swipe back to the previous view. I expected the ContentUnavailableView to link without any of these issues. Any guidance would be greatly appreciated.
0
0
140
3w
Inline Widget Displays Custom Image Abnormally
I want to display my own image in an inline widget. Using the SwiftUI Image syntax doesn't show the image, so following advice from online forums, I used the syntax Image(uiImage: UIImage(named: String)). This successfully displays the image, but if I change the image file name in the app, the image doesn't update properly. I tested displaying the image file name using Text in the inline widget, and it correctly shows the updated file name from my app. So, my AppStorage and AppGroups seem to be working correctly. I'd like to ask if there's a way to update my images properly and if there's an alternative method to display images without converting them to UIImage. Thanks.
0
0
157
3w
.fullScreenCover Incorrectly Dismissed
Hi, thought I'd share some feedback (which was also sent to Apple) publicly in case anyone else is experiencing the same issue or has an idea of how to circumvent the issue while Apple investigates. TLDR: Views presented with the .fullScreenCover modifier can be incorrectly dismissed when a child view presented with a .sheet modifier inside the .fullScreenCover is dismissed. The intended behavior is that the child sheet views can be dismissed without dismissing the parent full screen cover views. It appears this bug has been present in versions of iOS 17 as well as iOS 18. Short of using something other than a .fullScreenCover to present the view, I'm still searching for a solution to this bug. Filing: FB14007758 Steps to Reproduce (see code below): Open a View in .fullScreenCover presentation In the view presented via the .fullScreenCover, add two sheet modifiers with two different views (e.g. SheetOneView, SheetTwoView) Toggle the presentation of SheetOneView and SheetTwoView randomly until the .fullScreenCover is incorrectly dismissed. Reproducible Code: import SwiftUI struct SheetOneView: View { var body: some View { Text("Sheet: 1") } } struct SheetTwoView: View { var body: some View { Text("Sheet: 2") } } struct FullScreenCoverView: View { @State var isSheetOnePresented = false @State var isSheetTwoPresented = false var body: some View { VStack(content: { Text("Full Screen Cover") HStack { Button("Open Sheet 1") { isSheetOnePresented = true } Button("Open Sheet 2") { isSheetTwoPresented = true } } .buttonStyle(.borderedProminent) .buttonBorderShape(.capsule) }) .sheet(isPresented: $isSheetOnePresented) { SheetOneView() } .sheet(isPresented: $isSheetTwoPresented) { SheetTwoView() } } } struct ContentView: View { @State var isFullScreenCoverPresented = false var body: some View { VStack { Button("Open Full Screen Cover") { isFullScreenCoverPresented = true } } .fullScreenCover(isPresented: $isFullScreenCoverPresented, content: { FullScreenCoverView() }) .padding() } }
1
0
179
3w
Inline Widget Displays Custom Image Abnormally
I want to display my own image in an inline widget. Using the SwiftUI Image syntax doesn't show the image, so following advice from online forums, I used the syntaxImage(uiImage: UIImage(named: String))This successfully displays the image, but if I change the image file name in the app, the image doesn't update properly. I tested displaying the image file name using Text in the inline widget, and it correctly shows the updated file name from my app. So, my AppStorage and AppGroups seem to be working correctly. I'd like to ask if there's a way to update my images properly and if there's an alternative method to display images without converting them to UIImage. Thanks.
0
0
125
3w