Post

Replies

Boosts

Views

Activity

Reply to How do I add a Background Image behind a NavigatinLink
I'm assuming you mean change the List background to a custom image, since you are already changing the NavigationLink background with this: .listRowBackground(Color.black) In iOS 16, List no longer relies on UITableView, so your appearance proxy workarounds won't work. Instead, a new modifier, scrollContentBackground(_:), was introduced to remove the default background of a List and let you customise it with whatever view you wanted. You would use it like this: List(...) { ... } .scrollContentBackground(.hidden) // new in iOS 16 .background { Image("ImageName") .resizable() .scaledToFill() }
Topic: UI Frameworks SubTopic: SwiftUI Tags:
Sep ’22
Reply to EditMode Example not working
I've found that editMode works very strangely and only some of the time when you know how it works. Try extracting the parts that access the editMode property from the container that changes based on it, like List/Form. // container that does editing // changes based on editMode Form { EditingView() // extract to new view } // EditingView @Environment(\.editMode) private var editMode if editMode?.wrappedValue.isEditing == true { Text("Editing") } else { Text("Not Editing") }
Topic: UI Frameworks SubTopic: SwiftUI Tags:
Sep ’22
Reply to Sample code doesn't compile as contextAction has been replaced
What is the actual problem? Which sample code fails to compile? The old modifier, contextAction(forSelectionType:action:), was removed and its functionality was added to the contextMenu(forSelectionType:menu:primaryAction:) modifier. It is now used like this: .contextMenu(forType: Book.ID.self, menu: { _ in }) { books in // perform primary action } That's just what happens during the beta period: things are added, removed and modified. It's the final version that counts.
Topic: UI Frameworks SubTopic: SwiftUI Tags:
Sep ’22
Reply to Hyperlinks open in Web browser instead of embedded WKWebView using Swift5/SwiftUI
You simply need to use the WKNavigationDelegate to detect when there has been a navigation request (i.e. clicked on a link). You will need a class for this and that is where UIViewRepresentable.Coordinator comes in. You can implement it like this: struct NewsItemWebView: UIViewRepresentable {     var text: String     func makeUIView(context: Context) -> WKWebView {         let webView = WKWebView()         webView.navigationDelegate = context.coordinator         return webView     }     func updateUIView(_ webView: WKWebView, context: Context) {         ...     }     func makeCoordinator() -> Coordinator {         Coordinator()     } } extension ItemWebView {     @MainActor class Coordinator: NSObject, WKNavigationDelegate { // used the async method so you don't forget to call a completion handler // you can still use the completion handler method         func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction) async -> WKNavigationActionPolicy {             if let url = navigationAction.request.url, /* should `url` be opened in Safari */, await UIApplication.shared.open(url) {                 return .cancel             } else {                 return .allow             }         }     } } You will need to check the navigation request's url to see if it should be opened in Safari. This will prevent opening the originally loaded content in Safari instead of the app.
Topic: UI Frameworks SubTopic: SwiftUI Tags:
Oct ’22
Reply to SwiftUI on macOS: double tap on list item
In macOS Ventura, a new modifier, contextMenu(forSelectionType:menu:primaryAction:), was introduced to allow for a primary action to executed in selection-based containers along with the standard context menu. List(selection: $selectedItem) { ... } .contextMenu(forSelectionType: String.self, menu: { _ in }) { // double tap action } Single tap selection still works as well as the double tap action (specific to macOS). There was a contextAction(forSelectionType:action:) modifier originally which was removed and merged with the context menu one. I'm not sure why but it does mean you have to pass in an empty closure to the menu parameter if you want the same functionality.
Topic: UI Frameworks SubTopic: SwiftUI Tags:
Oct ’22
Reply to Error: "'async' call in an autoclosure that does not support concurrency"
Your QuotesViewModelImpl.init is marked as being async, and this is causing the issue. When you create your vm property, you are using the StateObject property wrapper which is initialised with this: init(wrappedValue thunk: @autoclosure @escaping () -> ObjectType) // ObjectType ends up being your QuotesViewModelImpl QuotesViewModelImpl needs to be initialised asynchronously, but in a place that doesn't support concurrency – no async – so you can't use that initialiser. Since there is nothing in that initialiser that needs to be executed asynchronously (i.e. called with await), I suggest you remove the async.
Topic: UI Frameworks SubTopic: SwiftUI Tags:
Oct ’22
Reply to How to open settings programmatically in Swift
You can access your app's settings page URL from the UIApplication.openSettingsURLString property. Use it like this: Button("Open Settings") { // Get the settings URL and open it if let url = URL(string: UIApplication.openSettingsURLString) { UIApplication.shared.open(url) } } There is currently no way to deep link directly to your app's location settings. iOS 16 did, however, introduce a UIApplication.openNotificationSettingsURLString property for the notifications settings section, so maybe the location settings URL is possible in the future, or through this.
Topic: UI Frameworks SubTopic: SwiftUI Tags:
Oct ’22
Reply to How to disable multiple TapGestures from being recognized simultaneously in SwiftUI
New in iOS 16 is a contextMenu(forSelectionType:menu:primaryAction:) modifier which accepts a primaryAction closure that is run, for example, when the user taps on a list row. You do, however, need to bind your list's selection value to a stored @State property. Can can use it like this: @State private var selectedNum: Int? List(selection: $selectedNum) { ForEach(1..<10) { i in Text("Hello, world!") } } .contextMenu(forSelectionType: Int.self, menu: { _ in }) { nums in print("Tapped: \(nums.first)") }
Topic: UI Frameworks SubTopic: SwiftUI Tags:
Oct ’22
Reply to What is the bar in Apple Music called in SwiftUI to switch between "Apple Music" and "Your Library"?
This is actually a feature that comes with searching called search scopes. In SwiftUI, you would combine the searchable(text:placement:prompt:) modifier with searchScopes(_:scopes:) to achieve this effect. Here's an example of how you would use it: @State private var searchText = "" @State private var selectedScope = "Option 1" let allScopes = ["Option 1", "Option 2", "Option 3"] ... .searchable(text: $searchText, prompt: "Search for something") .searchScopes($selectedScope) { ForEach(allScopes, id: \.self) { scope in Text(scope) } } Check out the documentation for each modifier, and I would highly recommend reading this article for more on searching in SwiftUI.
Topic: UI Frameworks SubTopic: SwiftUI Tags:
Oct ’22
Reply to Merge An Array Item's Array Property Based On Property
So, you have an array of City objects, each with a name and an array of Business objects. You want to have it so that cities with the same name (duplicates) are merged together, along with their businesses. Example: let business1 = Business(name: "Business 1") let business2 = Business(name: "Business 2") let business3 = Business(name: "Business 3") let business4 = Business(name: "Business 4") // before let cities = [ City(name: "City 1", businesses: [business1, business2]), City(name: "City 2", businesses: [business1, business2]), City(name: "City 1", businesses: [business3, business4]) ] // after let cities = [ City(name: "City 1", businesses: [business1, business2, business3, business4]), City(name: "City 2", businesses: [business1, business2]) ] If this is correct, then we can keep going. Something like this can work: // make City Equatable using only its name // this is how the example differentiates between two cities struct City: Equatable { ... static func == (lhs: City, rhs: City) -> Bool { lhs.name == rhs.name } } // this is the cities array without duplicate cities and with merged businesses let newCities: [City] = cities.reduce([]) { result, city in     var newResult = result     if let index = result.firstIndex(of: city) { // gets messy with optionals         newResult[index].businesses?.append(contentsOf: city.businesses ?? [])     } else {         newResult.append(city)     } return newResult } Hopefully, this will work for your use case.
Topic: UI Frameworks SubTopic: SwiftUI Tags:
Oct ’22
Reply to How to register my app for openURL()
Check out this article, particularly the "Register your URL scheme" section.
Topic: UI Frameworks SubTopic: SwiftUI Tags:
Replies
Boosts
Views
Activity
Sep ’22
Reply to How do I make this just make the picker visible?
You can just remove the background colour for the list row, like this: Picker(...) { ... } .pickerStyle(.segmented) .listRowBackground(Color.clear) .listRowInsets(.init()) // optional
Topic: UI Frameworks SubTopic: SwiftUI Tags:
Replies
Boosts
Views
Activity
Sep ’22
Reply to How do I add a Background Image behind a NavigatinLink
I'm assuming you mean change the List background to a custom image, since you are already changing the NavigationLink background with this: .listRowBackground(Color.black) In iOS 16, List no longer relies on UITableView, so your appearance proxy workarounds won't work. Instead, a new modifier, scrollContentBackground(_:), was introduced to remove the default background of a List and let you customise it with whatever view you wanted. You would use it like this: List(...) { ... } .scrollContentBackground(.hidden) // new in iOS 16 .background { Image("ImageName") .resizable() .scaledToFill() }
Topic: UI Frameworks SubTopic: SwiftUI Tags:
Replies
Boosts
Views
Activity
Sep ’22
Reply to NavigationSplitView not available in Mac Catalyst 16
Xcode 14.0.1 includes everything you need to create amazing apps for all Apple platforms. It includes SDKs for iOS 16, iPadOS 16, tvOS 16, watchOS 9, and macOS 12.3. Use Xcode 14.0 beta 6 or Xcode 14.1 beta 3 instead.
Topic: UI Frameworks SubTopic: SwiftUI Tags:
Replies
Boosts
Views
Activity
Sep ’22
Reply to EditMode Example not working
I've found that editMode works very strangely and only some of the time when you know how it works. Try extracting the parts that access the editMode property from the container that changes based on it, like List/Form. // container that does editing // changes based on editMode Form { EditingView() // extract to new view } // EditingView @Environment(\.editMode) private var editMode if editMode?.wrappedValue.isEditing == true { Text("Editing") } else { Text("Not Editing") }
Topic: UI Frameworks SubTopic: SwiftUI Tags:
Replies
Boosts
Views
Activity
Sep ’22
Reply to Sample code doesn't compile as contextAction has been replaced
What is the actual problem? Which sample code fails to compile? The old modifier, contextAction(forSelectionType:action:), was removed and its functionality was added to the contextMenu(forSelectionType:menu:primaryAction:) modifier. It is now used like this: .contextMenu(forType: Book.ID.self, menu: { _ in }) { books in // perform primary action } That's just what happens during the beta period: things are added, removed and modified. It's the final version that counts.
Topic: UI Frameworks SubTopic: SwiftUI Tags:
Replies
Boosts
Views
Activity
Sep ’22
Reply to Hyperlinks open in Web browser instead of embedded WKWebView using Swift5/SwiftUI
You simply need to use the WKNavigationDelegate to detect when there has been a navigation request (i.e. clicked on a link). You will need a class for this and that is where UIViewRepresentable.Coordinator comes in. You can implement it like this: struct NewsItemWebView: UIViewRepresentable {     var text: String     func makeUIView(context: Context) -> WKWebView {         let webView = WKWebView()         webView.navigationDelegate = context.coordinator         return webView     }     func updateUIView(_ webView: WKWebView, context: Context) {         ...     }     func makeCoordinator() -> Coordinator {         Coordinator()     } } extension ItemWebView {     @MainActor class Coordinator: NSObject, WKNavigationDelegate { // used the async method so you don't forget to call a completion handler // you can still use the completion handler method         func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction) async -> WKNavigationActionPolicy {             if let url = navigationAction.request.url, /* should `url` be opened in Safari */, await UIApplication.shared.open(url) {                 return .cancel             } else {                 return .allow             }         }     } } You will need to check the navigation request's url to see if it should be opened in Safari. This will prevent opening the originally loaded content in Safari instead of the app.
Topic: UI Frameworks SubTopic: SwiftUI Tags:
Replies
Boosts
Views
Activity
Oct ’22
Reply to Tuck button under navigation bar on watchOS like Mail app
You can place the button in the toolbar with the ToolbarItemPlacement.primaryAction placement. .toolbar { ToolbarItem(placement: .primaryAction) { // place button here } }
Topic: UI Frameworks SubTopic: SwiftUI Tags:
Replies
Boosts
Views
Activity
Oct ’22
Reply to SwiftUI on macOS: double tap on list item
In macOS Ventura, a new modifier, contextMenu(forSelectionType:menu:primaryAction:), was introduced to allow for a primary action to executed in selection-based containers along with the standard context menu. List(selection: $selectedItem) { ... } .contextMenu(forSelectionType: String.self, menu: { _ in }) { // double tap action } Single tap selection still works as well as the double tap action (specific to macOS). There was a contextAction(forSelectionType:action:) modifier originally which was removed and merged with the context menu one. I'm not sure why but it does mean you have to pass in an empty closure to the menu parameter if you want the same functionality.
Topic: UI Frameworks SubTopic: SwiftUI Tags:
Replies
Boosts
Views
Activity
Oct ’22
Reply to Error: "'async' call in an autoclosure that does not support concurrency"
Your QuotesViewModelImpl.init is marked as being async, and this is causing the issue. When you create your vm property, you are using the StateObject property wrapper which is initialised with this: init(wrappedValue thunk: @autoclosure @escaping () -> ObjectType) // ObjectType ends up being your QuotesViewModelImpl QuotesViewModelImpl needs to be initialised asynchronously, but in a place that doesn't support concurrency – no async – so you can't use that initialiser. Since there is nothing in that initialiser that needs to be executed asynchronously (i.e. called with await), I suggest you remove the async.
Topic: UI Frameworks SubTopic: SwiftUI Tags:
Replies
Boosts
Views
Activity
Oct ’22
Reply to How to open settings programmatically in Swift
You can access your app's settings page URL from the UIApplication.openSettingsURLString property. Use it like this: Button("Open Settings") { // Get the settings URL and open it if let url = URL(string: UIApplication.openSettingsURLString) { UIApplication.shared.open(url) } } There is currently no way to deep link directly to your app's location settings. iOS 16 did, however, introduce a UIApplication.openNotificationSettingsURLString property for the notifications settings section, so maybe the location settings URL is possible in the future, or through this.
Topic: UI Frameworks SubTopic: SwiftUI Tags:
Replies
Boosts
Views
Activity
Oct ’22
Reply to How to disable multiple TapGestures from being recognized simultaneously in SwiftUI
New in iOS 16 is a contextMenu(forSelectionType:menu:primaryAction:) modifier which accepts a primaryAction closure that is run, for example, when the user taps on a list row. You do, however, need to bind your list's selection value to a stored @State property. Can can use it like this: @State private var selectedNum: Int? List(selection: $selectedNum) { ForEach(1..<10) { i in Text("Hello, world!") } } .contextMenu(forSelectionType: Int.self, menu: { _ in }) { nums in print("Tapped: \(nums.first)") }
Topic: UI Frameworks SubTopic: SwiftUI Tags:
Replies
Boosts
Views
Activity
Oct ’22
Reply to What is the bar in Apple Music called in SwiftUI to switch between "Apple Music" and "Your Library"?
This is actually a feature that comes with searching called search scopes. In SwiftUI, you would combine the searchable(text:placement:prompt:) modifier with searchScopes(_:scopes:) to achieve this effect. Here's an example of how you would use it: @State private var searchText = "" @State private var selectedScope = "Option 1" let allScopes = ["Option 1", "Option 2", "Option 3"] ... .searchable(text: $searchText, prompt: "Search for something") .searchScopes($selectedScope) { ForEach(allScopes, id: \.self) { scope in Text(scope) } } Check out the documentation for each modifier, and I would highly recommend reading this article for more on searching in SwiftUI.
Topic: UI Frameworks SubTopic: SwiftUI Tags:
Replies
Boosts
Views
Activity
Oct ’22
Reply to TabView Item's Background Colors Behaves Differently in SwiftUI
This isn’t a SwiftUI or device type problem, it’s to do with your Accessibility settings. Go to Settings > Accessibility > Display & Text Size and set the Button Shapes toggle to false. This should fix your problem.
Topic: UI Frameworks SubTopic: UIKit Tags:
Replies
Boosts
Views
Activity
Oct ’22
Reply to Merge An Array Item's Array Property Based On Property
So, you have an array of City objects, each with a name and an array of Business objects. You want to have it so that cities with the same name (duplicates) are merged together, along with their businesses. Example: let business1 = Business(name: "Business 1") let business2 = Business(name: "Business 2") let business3 = Business(name: "Business 3") let business4 = Business(name: "Business 4") // before let cities = [ City(name: "City 1", businesses: [business1, business2]), City(name: "City 2", businesses: [business1, business2]), City(name: "City 1", businesses: [business3, business4]) ] // after let cities = [ City(name: "City 1", businesses: [business1, business2, business3, business4]), City(name: "City 2", businesses: [business1, business2]) ] If this is correct, then we can keep going. Something like this can work: // make City Equatable using only its name // this is how the example differentiates between two cities struct City: Equatable { ... static func == (lhs: City, rhs: City) -> Bool { lhs.name == rhs.name } } // this is the cities array without duplicate cities and with merged businesses let newCities: [City] = cities.reduce([]) { result, city in     var newResult = result     if let index = result.firstIndex(of: city) { // gets messy with optionals         newResult[index].businesses?.append(contentsOf: city.businesses ?? [])     } else {         newResult.append(city)     } return newResult } Hopefully, this will work for your use case.
Topic: UI Frameworks SubTopic: SwiftUI Tags:
Replies
Boosts
Views
Activity
Oct ’22