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

Post

Replies

Boosts

Views

Activity

Mapkit and swiftui
I have updated my map code so that now I have a region that is set as a state var in my strict. My map links to this state var. the problem is now I want to update my map based on my long and last variables that are passed to the struct is there a way to do this - going crazy trying to do this
3
0
4.4k
Jun ’20
Migrating existing SwiftUI apps to the new multi platform template
I have an iOS 13 app that I’m hoping to release soon that is written entirely in SwiftUI. If I was starting from scratch today, I’d obviously use the new multi platform template which looks awesome.... But since I’m not starting from scratch, what are the recommendations/best practices for existing apps? Is there a path for migrating existing apps to take advantage of the new app structure (below) when moving to iOS 14? @main struct HelloWorld: App { var body: some Scene { WindowGroup { Text(“Hello, world!”).padding() } } }
2
0
1.8k
Jun ’20
Prevent dismissal of sheet in SwiftUI
I'd like to emulate the behavior of UIViewController.isModalInPresentation in SwiftUI. In my first attempt, I defined the following view: struct ModalView<Content: View>: UIViewControllerRepresentable { 		var content: () -> Content 		func makeUIViewController(context: Context) -> UIHostingController<Content> { 				let controller = UIHostingController(rootView: content()) 				controller.isModalInPresentation = true 				return controller 		} 		func updateUIViewController(_ imagePickerController: UIHostingController<Content>, context: Context) {} } From my main app view, I then present the ModalView as a sheet: struct ContentView: View { 		@State 		var presentSheet: Bool = true 		var body: some View { 				Text("Hello, world!") 						.sheet(isPresented: $presentSheet) { 								ModalView { 										Text("Sheet") 								} 						} 		} } But the user is still able to dismiss the ModalView by swiping down. I would expect this sheet to be non-dismissible. Is anything like this supposed to work? If not, is there some other way to prevent the dismissal of a sheet in SwiftUI? The closest workaround I've found is to apply .highPriorityGesture(DragGesture()) to the content of the sheet, but swiping down with two fingers still works.
5
1
8.8k
Jun ’20
LinkDylibError when previewing SwiftUI view from a package.
I have two (local) Swift packages (both with a single library product): RemoteImage, which defines setImage(from:) function on UIImageView and SatelitUI package which directly depends on the first one and defines some views. But when I'm trying to preview views from the second package I'm getting the following error: linker command failed with exit code 1 (use -v to see invocation) LinkDylibError: Failed to build TrailerView.swift Linking failed: linker command failed with exit code 1 (use -v to see invocation) ld: warning: directory not found for option '-F/Applications/Xcode-beta.app/Contents/SharedFrameworks-iphonesimulator' Undefined symbols for architecture x86_64:   "(extension in RemoteImage):__C.UIImageView.setImage(from: Foundation.URL?) -> ()", referenced from:       (extension in SatelitUI_PreviewReplacement_TrailerView_2):SatelitUI.TrailerView.(previewupdate in _8C3731B0EF007627509BEEB93277D681)(with: SatelitUI.Trailer?) -> () in TrailerView.2.preview-thunk.o ld: symbol(s) not found for architecture x86_64 clang: error: linker command failed with exit code 1 (use -v to see invocation) Apparently, Xcode fails to link the library from the first package because it's dynamic. Static linking works as expected. It's a bug I believe?
2
1
1.7k
Jun ’20
Swift UI on iOS 14 not assigning new object to @State property
On iOS 13 I used to use optional @State properties to adapt views. In my case, the presented view would either create a new object (an assignment) if the state that is passed into it is nil, or edit the assignment if an assignment was passed in. This would be done in the action block of a Button and it worked beautifully. On iOS 14 / Xcode 12 this no longer seems to work. Given the following code which creates a new assignment and passes it into the editor view when the user taps a "New Assignment" button, the value of assignment remains nil. Is anyone else experiencing similar behaviour? struct ContentView: View { 		@Environment(\.managedObjectContext) var context 		@State var assignmentEditorIsPresented = false 		@State var assignment: Assignment? = nil 		var Body: some View { 				[...] 				Button("New Assignment", action: { 						self.assignment = Assignment(context: context) 						self.assignmentEditorIsPresented = true 				}) 				.sheet(isPresented: assignmentEditorIsPresented) { 						[...] 				} 		} } What's even weirder is that I tried adding a random piece of state, an Int, to this view and modifying it right before the assignment state (between lines 9 and 10) and it didn't change either.
20
3
11k
Jun ’20
SwiftUI Scene with a single window on macOS
Is it possible to only allow a single window instance on macOS? WindowGroup/DocumentGroup allow the user to create multiple instances of a window. I'd like to only allow one, for an Onboarding sequence. I've checked the Scene documentation - https://developer.apple.com/documentation/swiftui/scene, and it appears the only types conforming to the Scene protocol are WindowGroup, DocumentGroup and Settings. How can I create a single Window in a SwiftUI App? An example use case: struct TutorialScene: Scene {   var body: some Scene { 	// I don't want to allow multiple windows of this Scene! 	WindowGroup { 		TutorialView() 	}	 }
6
0
4.4k
Aug ’20
How should I access @AppStorage and @SceneStorage values outside of views?
The two property wrappers @AppStorage and @SceneStorage are great because you can simply redeclare a property in multiple views to share the value and automatically update other views. But how should I access those same values outside of views? I have helper functions which are used in multiple views and which change behaviour based on those stored properties. I believe I could use the old NSUserDefaults.standard to reference the @AppStorage values, but is that the "right" way to do it, and how do I access @SceneStorage values?
8
2
9.5k
Aug ’20
Swiftui Custom Fonts not showing
Hello, My Custom fonts are not showing in SwiftUI. I am all up to date on all of my software and I have added my TTF's to a fonts folder in my collection. I also added the "Fonts provided by application" array type to my info.plist and the fonts as elements. Here is my code. I have no idea what I'm doing wrong. Is there a bug in the latest version of Swiftui? Text("Hello World") 			.font(.custom("VervelleScript-lgxR0", size: 36))
6
1
7.5k
Sep ’20
SwiftUI negative kerning cuts off font
Hey there! Got a question about font kerning: When adding a negative kerning to a text (changes via user input) the last character sometimes gets cut off: dropbox.com/s/49ucdzk8m4k61sj/fontproblem1.png?dl=0 dropbox.com/s/vmklvxp510wjeak/fontproblem2.png?dl=0 What i do is the following: Text("\(pos, specifier: "%.1f")") 	.font(.system(size: 100,design: .serif)) 	.fontWeight(.bold) 	.kerning(-5) When i remove the kerning it works, but as i understood the kerning keeps the letters as they are? Is there an alternative way of doing it?
2
0
1.1k
Oct ’20
Why does same code work differently within SwiftUI Life Cycle and UIKit App Delegate Life Cycle?
Introduction I created a simple app to test enabling Sign In with Google using Observable Objects in a SwiftUI Application. However, the app only functions properly (displaying the signed in user's name and email) with a UIKit App Delegate Life Cycle. The code of the App file for the SwiftUI life cycle and that of the app delegate and scene delegate files of the UIKit App Delegate life cycle should function identical; however, they do not. Project Code SwiftUI Lift Cycle AppDelegate import UIKit import SwiftUI import GoogleSignIn class AppDelegate: NSObject, UIApplicationDelegate { /* GoogleDelegate() is the observable object */ let googleDelegate = GoogleDelegate() func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool { GIDSignIn.sharedInstance()?.clientID = "CLIENT_ID" GIDSignIn.sharedInstance()?.delegate = googleDelegate return true } func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool { return GIDSignIn.sharedInstance().handle(url) } } App @main struct WidgiTubeApp: App { @UIApplicationDelegateAdaptor(AppDelegate.self) var appDelegate var window: UIWindow? { guard let scene = UIApplication.shared.connectedScenes.first, let windowSceneDelegate = scene.delegate as? UIWindowSceneDelegate, let window = windowSceneDelegate.window else {             return nil } return window } @Environment(\.scenePhase) private var scenePhase let googleDelegate = (UIApplication.shared.delegate as! AppDelegate).googleDelegate var body: some Scene { WindowGroup { GoogleSignInView() .environmentObject(googleDelegate) }.onChange(of: scenePhase) { (phase) in switch phase { case .active: GIDSignIn.sharedInstance().presentingViewController = window?.rootViewController window?.makeKeyAndVisible() case .inactive: case .background: default: } } } } Using the SwiftUI Life Cycle the User Is signed in; however, the information does not update in the SwiftUI view. (The view is identical between the SwiftUI Life Cycle and UIKit Application Delegate Life Cycle.) UIKit Application Delegate Life Cycle App Delegate DidFinishLaunchingWithOptions GIDSignIn.sharedInstance().clientID = "CLIENT_ID" GIDSignIn.sharedInstance().delegate = googleDelegate return true OpenURL return GIDSignIn.sharedInstance().handle(url) Scene Delegate SceneWillConnectTo let googleDelegate = (UIApplication.shared.delegate as! AppDelegate).googleDelegate let contentView = ContentView().environmentObject(googleDelegate) if let windowScene = scene as? UIWindowScene { let window = UIWindow(windowScene: windowScene) window.rootViewController = UIHostingController(rootView: contentView) GIDSignIn.sharedInstance()?.presentingViewController = window.rootViewController self.window = window window.makeKeyAndVisible() } Conclusion Due to this, I have identified that there must be some issue that occurs when adapting the UIKit App Delegate code to the SwiftUI App Code. However, I cannot identify what the issue between the two life cycles is. It is my understanding that anything possible with the UIKit Delegate life cycle should theoretically be possible with SwiftUI. In the mean time, of course, there is no issue continuing with the UIKit Delegate; however, I was hoping to create a SwiftUI app. If anyone could help me identify where the issue lays between these two different life cycles, I would greatly appreciate it. Thanks!
1
0
1.7k
Nov ’20
SwiftUI/CoreData: Simultaneous accesses to 0x7f92efc61cb8, but modification requires exclusive access
I'm working on an iOS app using SwiftUI and CoreData and am running into a problem that I cannot seem to figure out. To provide a little bit of information of what I am trying to do: I have two CoreData entities that have a One-To-Many relationship: Tarantula - A tarantula may molt many times (To Many) and when deleted, all of the molts shold also be removed (Cascade) Molt - A molt belongs to a single Tarantula (To One) and when deleted, should have the reference removed from the Tarantula (Nullify) I then have a view that lists all of the molts for a given Tarantula that allows adding and deleting molts. It looks like this: struct MoltListView: View { &#9;&#9;private static let DATE_FORMATTER: DateFormatter = { &#9;&#9;&#9;&#9;&#9;&#9;let d = DateFormatter() &#9;&#9;&#9;&#9;&#9;&#9;d.dateFormat = "MMM d, y" &#9;&#9;&#9;&#9;&#9;&#9;return d &#9;&#9;&#9;&#9;}() &#9;&#9; &#9;&#9;@Environment(\.managedObjectContext) private var viewContext &#9;&#9; &#9;&#9;@ObservedObject private var tarantula: Tarantula &#9;&#9;@FetchRequest private var molts: FetchedResults<Molt> &#9;&#9;@State private var userMessage: String = "" &#9;&#9;@State private var displayMessage: Bool = false &#9;&#9; &#9;&#9;init(tarantula: Tarantula) { &#9;&#9;&#9;&#9;self.tarantula = tarantula &#9;&#9;&#9;&#9;self._molts = FetchRequest(entity: Molt.entity(), &#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9; sortDescriptors: [NSSortDescriptor(keyPath: \Molt.date, ascending: false)], &#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9; predicate: NSPredicate(format: "tarantula = %@", tarantula)) &#9;&#9;} &#9;&#9; &#9;&#9;var body: some View { &#9;&#9;&#9;&#9;List { &#9;&#9;&#9;&#9;&#9;&#9;Section(header: Text("Summary")) { &#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;Text("\(molts.count) Molt\(molts.count == 1 ? "" : "s")") &#9;&#9;&#9;&#9;&#9;&#9;} &#9;&#9;&#9;&#9;&#9;&#9;Section(header: Text("Molts")) { &#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;NavigationLink(destination: MoltView(tarantula: tarantula, molt: Molt.newModel())) { &#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;Text("Add Molt").foregroundColor(.blue) &#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;} &#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;ForEach(molts, id: \.self) { molt in &#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;NavigationLink(destination: MoltView(tarantula: tarantula, molt: molt)) { &#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;Text(MoltListView.DATE_FORMATTER.string(from: molt.modelDate)) &#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;} &#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;} &#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;.onDelete(perform: deleteItems) &#9;&#9;&#9;&#9;&#9;&#9;} &#9;&#9;&#9;&#9;}.alert(isPresented: $displayMessage) { &#9;&#9;&#9;&#9;&#9;&#9;Alert(title: Text("Save Failure"), message: Text(userMessage), dismissButton: .default(Text("Ok"))) &#9;&#9;&#9;&#9;} &#9;&#9;} &#9;&#9; &#9;&#9;private func deleteItems(offsets: IndexSet) { &#9;&#9;&#9;&#9;withAnimation { &#9;&#9;&#9;&#9;&#9;&#9;offsets.map { molts[$0] }.forEach(viewContext.delete) &#9;&#9;&#9;&#9;&#9;&#9;do { &#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;try viewContext.save() &#9;&#9;&#9;&#9;&#9;&#9;} catch { &#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;viewContext.rollback() &#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;userMessage = "\(error): \(error.localizedDescription)" &#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;displayMessage.toggle() &#9;&#9;&#9;&#9;&#9;&#9;} &#9;&#9;&#9;&#9;} &#9;&#9;} } The error I am experiencing comes from whenever I try to delete a molt from the list view. The app instantly crashes and the error is: Simultaneous accesses to 0x7f92efc61cb8, but modification requires exclusive access Find the complete error here: error - https://developer.apple.com/forums/content/attachment/6d74dcde-d82b-4024-ade0-5936d8926488 I have tried removing the animation block and have played around with removing different UI components/restructuring. The only way I have been able to prevent this error is to remove the delete rule on the Molt->Tarantula relationship from Nullify to No Action. However, this seems more like a hack to me instead of a fix. Was hoping for some help on this issue.
7
0
4.1k
Dec ’20
What is the correct method for renaming a file in the app's container using the Swiftui 2.0 Document based template?
I've been using the new template for a document-based SwiftUI app. While you get a lot of file-management "for free" in the new template, as it stands in the iOS version users have to back out of the file to the file browser to change the filename. I want to create an opportunity for the user to rename the file while it is open. Here's a sample project focused on the issue: https://github.com/stevepvc/DocumentRenamer In the code, I've added to the template code a simple UI with a textfield for the user to enter a new name. When the user hits the "rename" button, the app checks to see if the URL with that name component is available, appending a suffix if necessary to create a target url. func getTargetURL() -> URL { &#9;&#9;let baseURL&#9;=&#9;self.fileurl.deletingLastPathComponent() &#9;&#9;print("filename: \(self.filename)") &#9;&#9;print("fileURL: \(self.fileurl)") &#9;&#9;print("BaseURL: \(baseURL)") &#9;&#9;var target = URL(fileURLWithPath: baseURL.path + "/\(filename).exampletext") &#9;&#9;var nameSuffix = 1 &#9;&#9; &#9;&#9;while (target as NSURL).checkPromisedItemIsReachableAndReturnError(nil) { &#9;&#9;&#9;&#9; &#9;&#9;&#9;&#9;target = URL(fileURLWithPath: baseURL.path + "/\(filename)-\(nameSuffix).sermon") &#9;&#9;&#9;&#9;print("Checking: \(target)") &#9;&#9;&#9;&#9;nameSuffix += 1 &#9; } &#9;&#9;print("Available Target: \(target)") &#9;&#9;return target } It then attempts to rename the file, and this is when I am stuck. I have tried several methods, most recently the following: func changeFilename(){ &#9;&#9;let target&#9;= getTargetURL() &#9;&#9;var rv = URLResourceValues() &#9;&#9;let newFileName = target.deletingPathExtension().lastPathComponent &#9;&#9;rv.name = newFileName &#9;&#9;do { &#9;&#9;&#9;&#9;if fileurl.startAccessingSecurityScopedResource(){ &#9;&#9;&#9;&#9;&#9;&#9;try fileurl.setResourceValues(rv) &#9;&#9;&#9;&#9;&#9;&#9;fileurl.stopAccessingSecurityScopedResource() &#9;&#9;&#9;&#9;} &#9;&#9;} catch { &#9;&#9;&#9;&#9;print("Error:\(error)") &#9;&#9;} } But I keep getting the following error whenever I run the app on a device: Domain=NSCocoaErrorDomain Code=513 "You don’t have permission to save the file “Untitled” in the folder “DocumentRenamer”." I have also tried this without the startAccessingSecurityScopedResource() check, and alternatively have tried creating a helper class as follows: class FileMover: NSObject { func moveFile(originalURL: URL, updatedURL:URL) -> Bool { &#9;&#9;let coordinator = NSFileCoordinator(filePresenter: nil) &#9;&#9;var writingError: NSError? = nil &#9;&#9;var success : Bool = true &#9;&#9;print("moving file") &#9;&#9;coordinator.coordinate(writingItemAt: originalURL, options: NSFileCoordinator.WritingOptions.forMoving, error: &writingError, byAccessor: { (coordinatedURL) in &#9;&#9;&#9;&#9;do { &#9;&#9;&#9;&#9;&#9;&#9;try FileManager.default.moveItem(at: coordinatedURL, to: updatedURL) &#9;&#9;&#9;&#9;&#9;&#9;success = true &#9;&#9;&#9;&#9;&#9;&#9;print("file moved") &#9;&#9;&#9;&#9;&#9;&#9; &#9;&#9;&#9;&#9;} catch { &#9;&#9;&#9;&#9;&#9;&#9;print(error) &#9;&#9;&#9;&#9;&#9;&#9;success = false &#9;&#9;&#9;&#9;} &#9;&#9;}) return success &#9;&#9; } } But using this method locks up the app entirely. What is the correct method for renaming a file in the app's container, particularly using the new Swiftui Document based template?
3
3
2.6k
Dec ’20
ScrollViewReader scrollTo ignores withAnimation-Duration
I tried animating the scrollTo() like so, as described in the docs. - https://developer.apple.com/documentation/swiftui/scrollviewreader swift withAnimation { scrollProxy.scrollTo(index, anchor: .center) } the result is the same as if I do swift withAnimation(Animation.easeIn(duration: 20)) {     scrollProxy.scrollTo(progress.currentIndex, anchor: .center) } I tried this using the example from the ScrollViewReader docs. With the result that up and down scrolling has exactly the same animation. struct ScrollingView: View {     @Namespace var topID     @Namespace var bottomID     var body: some View {         ScrollViewReader { proxy in             ScrollView {                 Button("Scroll to Bottom") {                     withAnimation {                         proxy.scrollTo(bottomID)                     }                 }                 .id(topID)                 VStack(spacing: 0) {                     ForEach(0..100) { i in                         color(fraction: Double(i) / 100)                             .frame(height: 32)                     }                 }                 Button("Top") {                     withAnimation(Animation.linear(duration: 20)) {                         proxy.scrollTo(topID)                     }                 }                 .id(bottomID)             }         }     }     func color(fraction: Double) - Color {         Color(red: fraction, green: 1 - fraction, blue: 0.5)     } } struct ScrollingView_Previews: PreviewProvider {     static var previews: some View {         ScrollingView()     } }
11
5
4.1k
Apr ’21
fileImporter not showing
Hello, in my Mac Catalyst app, I have detail view with sections modeled as DisclosureGroups. The label view has a button, that shall trigger a file import view when pushed. The label view is defined as follows: swift HStack {         Text(LocalizedStringKey("Documents")).font(.title)         Spacer()         Button {           showFileImporter = false           // fix broken picker sheet           DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {             showFileImporter = true           }         } label: {           Image(systemName: "doc.badge.plus")             .padding(.horizontal, 10)         }         .disabled(!expanded)         .fileImporter(                       isPresented: $showFileImporter,               allowedContentTypes: [.data],           allowsMultipleSelection: false) { result in                       // add fileUrl.startAccessingSecurityScopedResource() before accessing file             NSLog("\(result)")           }       } Unfortunately the file import view is not showing, when the button is pushed, although the state changes to true. Does anybody have any hints? BTW the repo is available at https://github.com/thbonk/repti/tree/ui-refactoring The view in question is https://github.com/thbonk/repti/blob/ui-refactoring/Repti/Source/UI/Views/IndividualDetails/DocumentsSubview.swift Thanks &amp; Best regards Thomas
1
0
1.2k
May ’21
SwiftUI preview failing with failedToGenerateThunkInfo
I have an iOS app by using a swift package to hold most of the logic. However, the previews of SwiftUI views often fail with following error: HumanReadableSwiftError BuildError: failedToGenerateThunkInfo(Error Domain=com.apple.xcbuild Code=19 "could not generate preview info: noTargetBuildGraph" UserInfo={NSLocalizedDescription=could not generate preview info: noTargetBuildGraph}) To reproduce this, please clone https://github.com/pointfreeco/isowords and check for preview of ChangelogView.
10
0
3.1k
May ’21
AsyncImage - Cancelled Loading before View is Visible
I have been playing around with the new AsyncImage Api in SwiftUI I am using the initialiser that passes in a closure with the AsyncImagePhase, to view why an image may not load, when I looked at the error that is passed in if the phase is failure, the localised description of the error is "Cancelled" but this is happening before the view is being displayed. I am loading these images in a list, I imagine I am probably doing something which is causing the system to decide to cancel the loading, but I cannot see what. Are there any tips to investigate this further?
14
6
11k
Jun ’21
Conforming @MainActor class to Codable
How does one add Codable conformance to a class that needs to be isolated to the MainActor? For example, the following code gives compiler errors: @MainActor final class MyClass: Codable { var value: Int enum CodingKeys: String, CodingKey { case value } init(from decoder: Decoder) throws { // <-- Compiler error: Initializer 'init(from:)' isolated to global actor 'MainActor' can not satisfy corresponding requirement from protocol 'Decodable' let data = try decoder.container(keyedBy: CodingKeys.self) self.value = try data.decode(Int.self, forKey: .value) } func encode(to encoder: Encoder) throws { // <-- Compiler error: Instance method 'encode(to:)' isolated to global actor 'MainActor' can not satisfy corresponding requirement from protocol 'Encodable' var container = encoder.container(keyedBy: CodingKeys.self) try container.encode(value, forKey: .value) } } I'm definitely struggling to get my head around actors and @MainActor at the moment!
1
1
3.0k
Aug ’21
On Continue User Activity with Swift UI
Hi All, I'm very new to iOS development and Swift UI is my first coding language. I'm trying to link the users search results in Spotlight with the detail view that is stored in Core Data. I can search for users data in spotlight but when I tap on it, it's only appearing in the main view of the app. Is there anyways that I can use .onContinueUserActivity at the launch of the app or is there any different code that I have to use? I've searched for many articles but I couldn't get a solution. It would be good if anyone can share some links or guide here. Thank you. .onContinueUserActivity(DetailView.productUserActivityType) { userActivity in             if let product = try? userActivity.typedPayload(Product.self) {                 selectedProduct = product.id.uuidString             }         } I get this code from Apple's State restoration app but I can't use this with Core Data.
1
0
1.3k
Aug ’21
supplementarySidebarTrackingSeparatorItemIdentifier
I'm developing an iOS 14 Catalyst app and I'm trying to setup the window toolbar. I created a NSToolbar and assigned to the scene window titlebar property. var toolbarDelegate = ToolbarDelegate() func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) { #if targetEnvironment(macCatalyst) guard let windowScene = scene as? UIWindowScene else { return } let toolbar = NSToolbar(identifier: "main") toolbar.delegate = toolbarDelegate toolbar.displayMode = .iconOnly if let titlebar = windowScene.titlebar { titlebar.toolbar = toolbar titlebar.toolbarStyle = .unified titlebar.titleVisibility = .hidden } #endif } I then assigned some items to the toolbar via the toolbarDefaultItemIdentifiers delegate method. func toolbarDefaultItemIdentifiers(_ toolbar: NSToolbar) -> [NSToolbarItem.Identifier] { let identifiers: [NSToolbarItem.Identifier] = [ .toggleSidebar, .print, .flexibleSpace, .print ] return identifiers } This work as expected. Now, let's say that I want to align some items with the edges of the supplementary column. I found that there is an NSToolbarItem named supplementarySidebarTrackingSeparatorItemIdentifier. This item appears to allow us to align items with the supplementary column. If I do this: func toolbarDefaultItemIdentifiers(_ toolbar: NSToolbar) -> [NSToolbarItem.Identifier] { let identifiers: [NSToolbarItem.Identifier] = [ .toggleSidebar, .flexibleSpace, .print, .supplementarySidebarTrackingSeparatorItemIdentifier, .print, .flexibleSpace, .print ] return identifiers } I got the following result which is exactly what I want to achieve (the items are aligned with the supplementary column): But there are some issues. As you can see from the above image for some reason the background color of the toolbar on top of the supplementary column become white. But it's worse. If I resize the window the background instantly become gray: If I then scroll the content of the supplementary column the toolbar become white again. Another issue is that If I collapse the primary column the toolbar on top of the supplementary column loose the right separator line. Why? I tried to search some info online but if I try to search for supplementarySidebarTrackingSeparatorItemIdentifier I got only 5 results! One of these is Apple's official documentation page, which does not contain any info about the behaviour of this item: Apple documentation about supplementarySidebarTrackingSeparatorItemIdentifier At this point I wonder if this item is ready to be used in real apps. Someone has experience using the supplementarySidebarTrackingSeparatorItemIdentifier item? There is a way to align toolbar items with the supplementary column without having the above described issues? (different toolbar background color, missing toolbar separator line) Thank you
1
0
1.2k
Aug ’21