Explore the various UI frameworks available for building app interfaces. Discuss the use cases for different frameworks, share best practices, and get help with specific framework-related questions.

All subtopics
Posts under UI Frameworks topic

Post

Replies

Boosts

Views

Activity

A Summary of the WWDC25 Group Lab - UI Frameworks
At WWDC25 we launched a new type of Lab event for the developer community - Group Labs. A Group Lab is a panel Q&A designed for a large audience of developers. Group Labs are a unique opportunity for the community to submit questions directly to a panel of Apple engineers and designers. Here are the highlights from the WWDC25 Group Lab for UI Frameworks. How would you recommend developers start adopting the new design? Start by focusing on the foundational structural elements of your application, working from the "top down" or "bottom up" based on your application's hierarchy. These structural changes, like edge-to-edge content and updated navigation and controls, often require corresponding code modifications. As a first step, recompile your application with the new SDK to see what updates are automatically applied, especially if you've been using standard controls. Then, carefully analyze where the new design elements can be applied to your UI, paying particular attention to custom controls or UI that could benefit from a refresh. Address the large structural items first then focus on smaller details is recommended. Will we need to migrate our UI code to Swift and SwiftUI to adopt the new design? No, you will not need to migrate your UI code to Swift and SwiftUI to adopt the new design. The UI frameworks fully support the new design, allowing you to migrate your app with as little effort as possible, especially if you've been using standard controls. The goal is to make it easy to adopt the new design, regardless of your current UI framework, to achieve a cohesive look across the operating system. What was the reason for choosing Liquid Glass over frosted glass, as used in visionOS? The choice of Liquid Glass was driven by the desire to bring content to life. The see-through nature of Liquid Glass enhances this effect. The appearance of Liquid Glass adapts based on its size; larger glass elements look more frosted, which aligns with the design of visionOS, where everything feels larger and benefits from the frosted look. What are best practices for apps that use customized navigation bars? The new design emphasizes behavior and transitions as much as static appearance. Consider whether you truly need a custom navigation bar, or if the system-provided controls can meet your needs. Explore new APIs for subtitles and custom views in navigation bars, designed to support common use cases. If you still require a custom solution, ensure you're respecting safe areas using APIs like SwiftUI's safeAreaInset. When working with Liquid Glass, group related buttons in shared containers to maintain design consistency. Finally, mark glass containers as interactive. For branding, instead of coloring the navigation bar directly, consider incorporating branding colors into the content area behind the Liquid Glass controls. This creates a dynamic effect where the color is visible through the glass and moves with the content as the user scrolls. I want to know why new UI Framework APIs aren’t backward compatible, specifically in SwiftUI? It leads to code with lots of if-else statements. Existing APIs have been updated to work with the new design where possible, ensuring that apps using those APIs will adopt the new design and function on both older and newer operating systems. However, new APIs often depend on deep integration across the framework and graphics stack, making backward compatibility impractical. When using these new APIs, it's important to consider how they fit within the context of the latest OS. The use of if-else statements allows you to maintain compatibility with older systems while taking full advantage of the new APIs and design features on newer systems. If you are using new APIs, it likely means you are implementing something very specific to the new design language. Using conditional code allows you to intentionally create different code paths for the new design versus older operating systems. Prefer to use if #available where appropriate to intentionally adopt new design elements. Are there any Liquid Glass materials in iOS or macOS that are only available as part of dedicated components? Or are all those materials available through new UIKit and AppKit views? Yes, some variations of the Liquid Glass material are exclusively available through dedicated components like sliders, segmented controls, and tab bars. However, the "regular" and "clear" glass materials should satisfy most application requirements. If you encounter situations where these options are insufficient, please file feedback. If I were to create an app today, how should I design it to make it future proof using Liquid Glass? The best approach to future-proof your app is to utilize standard system controls and design your UI to align with the standard system look and feel. Using the framework-provided declarative API generally leads to easier adoption of future design changes, as you're expressing intent rather than specifying pixel-perfect visuals. Pay close attention to the design sessions offered this year, which cover the design motivation behind the Liquid Glass material and best practices for its use. Is it possible to implement your own sidebar on macOS without NSSplitViewController, but still provide the Liquid Glass appearance? While technically possible to create a custom sidebar that approximates the Liquid Glass appearance without using NSSplitViewController, it is not recommended. The system implementation of the sidebar involves significant unseen complexity, including interlayering with scroll edge effects and fullscreen behaviors. NSSplitViewController provides the necessary level of abstraction for the framework to handle these details correctly. Regarding the SceneDelagate and scene based life-cycle, I would like to confirm that AppDelegate is not going away. Also if the above is a correct understanding, is there any advice as to what should, and should not, be moved to the SceneDelegate? UIApplicationDelegate is not going away and still serves a purpose for application-level interactions with the system and managing scenes at a higher level. Move code related to your app's scene or UI into the UISceneDelegate. Remember that adopting scenes doesn't necessarily mean supporting multiple scenes; an app can be scene-based but still support only one scene. Refer to the tech note Migrating to the UIKit scene-based life cycle and the Make your UIKit app more flexible WWDC25 session for more information.
Topic: UI Frameworks SubTopic: General
0
0
884
Jun ’25
iOS 26 TabBar Remove Selected Capsule
I have subclassed UITabBar and created a custom look and feel for it. On iOS 18, the tab bar appears as expected. On iOS 26, however, a default Liquid Glass-style capsule selection indicator appears behind the selected tab item. I tried using UITabBarAppearance, including selectionIndicatorTintColor = .clear and selectionIndicatorImage = nil / empty image, but the capsule-style selected background still appears. Is this selection treatment part of the new default system rendering in iOS 26, and if so, is there any supported way to remove or disable it while still using UITabBar?
Topic: UI Frameworks SubTopic: UIKit Tags:
1
0
30
6h
Update FreeType to support the new Chinese font format
Beginning with macOS Sonoma, Apple introduced a novel font format for rendering Chinese text. Apps that use third-party libraries for text rendering continued to function, primarily without disruption, owing to some workarounds provided by the operating system. FreeType, one of the most widely used cross-platform libraries for text rendering, now supports this new format. Apps that use this library, regardless of whether they encountered issues with Chinese text or not, should update to the latest FreeType source from their git repository (https://gitlab.freedesktop.org/freetype/freetype), as this support is not yet available in a tagged release. Updating ensures that apps operate optimally with Chinese text as well as any other language that uses this new format. Because this support calls into Apple APIs that Apple introduced in macOS 15.4, iOS 18.4, and aligned watchOS, tvOS, and visionOS releases, set the deployment target when building FreeType to match that of your own app. This ensures that the new API calls fail gracefully on older OS versions rather than causing your app to crash on systems where those APIs are not available.
0
0
82
1d
Password autofill not respecting contentType of NSSecureTextField
We have a Mac app the allows customers to create a user account in our system. However, we have found that on the 'create account' screen, the system's password autofill is popping up for the "New Password" field. We don't want this, because they need to enter a new password, not pull one from the Passwords app. I built a test project with a basic UI and explicitly set the content type to None in the XIB. However, I can see when I put focus on the "New Password" NSSecureTextField, the system shows the passwords autofill popup. How can I explicitly suppress this on a per text field basis? (We are developing on macOS 26.3 right now with Xcode 26.3)
Topic: UI Frameworks SubTopic: AppKit
0
0
17
1d
DiffableDataSource hangs on apply
About a year ago, I developed and released an app on the App Store (I believe it was running on the Sequoia SDK at the time), and everything was working fine. I’m now revisiting the project using the newer Tahoe SDK, and I’m running into an issue with DiffableDataSource. Specifically, the app hangs and CPU usage spikes to 100% when applying snapshots. Has anyone experienced similar issues after upgrading to newer SDKs? Are there any recent changes or pitfalls with DiffableDataSource (e.g., threading, Hashable requirements, or snapshot handling) that I should be aware of? Any insights or suggestions would be greatly appreciated. extension Section { enum Identifier: Int, CaseIterable { case main } enum Item: Hashable { case file(FileViewData) } } struct FileViewData: Equatable, Hashable, Identifiable { let id: String let name: String var accessoryViewData: KTFDownloadAccessoryViewData init( id: String, name: String, accessoryViewData: KTFDownloadAccessoryViewData = .nothing ) { self.id = id self.name = name self.accessoryViewData = accessoryViewData } } public enum KTFDownloadAccessoryViewData: Equatable, Hashable { case nothing case selected(SelectedState) case completed public enum SelectedState: Equatable, Hashable { case nothing case waiting case downloading(Double) } } When I changed FileViewData as below, no hangs but item appearance doesn't change of course. struct FileViewData: Equatable, Hashable, Identifiable { let id: String let name: String var accessoryViewData: KTFDownloadAccessoryViewData init( id: String, name: String, accessoryViewData: KTFDownloadAccessoryViewData = .nothing ) { self.id = id self.name = name self.accessoryViewData = accessoryViewData } func hash(into hasher: inout Hasher) { hasher.combine(id) } static func == (lhs: FileViewData, rhs: FileViewData) -> Bool { return lhs.id == rhs.id } }
Topic: UI Frameworks SubTopic: UIKit Tags:
1
0
38
1d
NSDocument "saveToURL:ofType:..." is using outdated file type
These days I've observed a strange behavior in my document-based app on macOS: Its NSDocument class implementation is overwriting "saveToURL:ofType:forSaveOperation:completionHandler:", performing some additional checks and calling super by passing the original parameters. As my app is supporting various file formats for writing (and exporting those UTIs) the user can open a file in one format and save it to another. NSDocument is calling the mentioned methods implicitly after completing the "Save as..." dialog. If this happens, the passed-on fileType is still the one of format #1, although the file is saved with the file name extension of format #2. This hick-up is not directly obvious to the user. But if the file is re-saved (e.g. after modifications), Cocoa is trying to extend the sandbox for the URL of type #1, and fails with the following error message at the Xcode console: -[STBDocument saveToURL:ofType:forSaveOperation:completionHandler:] [Line 521] typeName: com.janome.jef -[STBDocument saveToURL:ofType:forSaveOperation:completionHandler:] [Line 523] targetTypeUTI: com.tajima.dst NSFileSandboxingRequestRelatedItemExtension: Failed to issue extension for /Users/matthias/Desktop/Ohne Titel.jef because: Error Domain=NSPOSIXErrorDomain Code=3 "No such process" -[NSFileCoordinator itemAtURL:willMoveToURL:] could not get a sandbox extension. oldURL: file:///Users/matthias/Desktop/Ohne%20Titel.dst, newURL: file:///Users/matthias/Desktop/Ohne%20Titel.jef I'm currently fixing this issue by determining the UTType for the new file name extension and passing it to super. Unfortunately I have no idea how long this issue was already present, and cannot replicate it with a sample app based on Apple's Xcode 26 template (too many differences to my >15 years old app) - so I won't file a bug report. Take this post just for information in case someone else is facing a similar situation...
0
0
36
1d
Initial presentation of popover hangs when shown from a button in the toolbar
I have a simple reproducer here: struct ContentView: View { @State private var isOn = false @State private var isPresented = false var body: some View { NavigationStack { Color.blue .toolbar { ToolbarItem(placement: .topBarTrailing) { Button("Press here") { isPresented = true } .popover(isPresented: $isPresented) { Color.green .frame(idealWidth: 400, idealHeight: 500) .presentationCompactAdaptation(.popover) } } } } } } When I tap on the button in the toolbar you can see there is a hang then the popover shows. Then every time after there is no longer a hang so this seems like a bug. Any ideas? I'm using Xcode 26.3 and a iPad Pro 13-inch (M5) (26.4) simulator.
1
3
83
5h
X button disappeared on iPadOS 26.4 in MFMailComposeViewController
I’m using MFMailComposeViewController to send emails from my app. Since updating to iPadOS 26.4, there is no way to cancel the mail composer because the “X” button in the top-left corner has disappeared. On iPhone with iOS 26.4, everything still seems to work as expected. Is this a known issue, or am I missing something? Has anyone else experienced this, or found a workaround?
Topic: UI Frameworks SubTopic: UIKit
2
0
131
2d
NSTextAttachment.character symbol suddenly not available anymore resulting in compiler error
I published the latest update of my AppKit app in September with macOS 26.0. I just wanted to create a new update, but compiling on macOS 26.4 now fails because of the symbol NSTextAttachment.character which is referenced in my code. The error is Type 'NSTextAttachment' has no member 'character' I've never experienced before that a symbol suddenly is not available anymore without even a deprecation notice from one OS release to the next, let alone a minor release. Is this a bug in macOS or Xcode, or should I start worrying about symbols becoming unavailable anytime?
2
0
183
1d
Potentially Unfair Limitation for Third-Party Keyboard Developers
When developing a custom keyboard on iOS, even after enabling Full Access (RequestsOpenAccess = true), it is still not possible to record audio — the recording simply does not start. This is despite the fact that: the user is explicitly warned the user provides informed consent by enabling Full Access According to Apple’s documentation: https://developer.apple.com/documentation/uikit/configuring-open-access-for-a-custom-keyboard “However, with RequestsOpenAccess set to true, the keyboard has all the capabilities in the preceding list.” At the same time, the preceding list includes: “No access to microphone and speaker” This creates ambiguity. The wording suggests that enabling Full Access should lift prior restrictions, yet in practice, microphone access remains unavailable to third-party keyboards. Why this is concerning With Full Access enabled, a keyboard already has: network access the ability to transmit user input From a privacy standpoint, this is already highly sensitive. Preventing microphone access while allowing these capabilities appears inconsistent. Meanwhile, Apple’s own system keyboard supports voice dictation, which creates a functional gap between first-party and third-party keyboards. Competition perspective This raises a broader question about equal access to platform capabilities. Restricting third-party keyboards from using the microphone — while first-party solutions can — may be seen as: unequal treatment of developers a limitation of competition in input methods Such differences are increasingly scrutinized under EU regulations like the Digital Markets Act and Article 102 TFEU, which emphasize fair access to platform features and prohibit self-preferencing by dominant platforms. Request for clarification Is microphone access intentionally restricted for all third-party keyboards, even with Full Access enabled? If so, what is the technical or policy justification? Are there plans to provide a secure and user-consented way to enable audio input for custom keyboards? Clarification on this would help developers better understand platform limitations and design decisions.
0
0
62
2d
UITextView cursor sometimes jumps up when pressing arrow down key and setting typingAttributes
My app uses TextKit 1 and unfortunately still cannot migrate to TextKit 2 because of some bugs (for instance in FB17103305 I show how NSTextView.shouldDrawInsertionPoint has no effect, but I opened that feedback exactly one year ago and it still has no answer). Unfortunately TextKit 1 has another bug which causes the text cursor to jump unpredictably up or down when pressing the arrow keys and setting UITextView.typingAttributes. Run the code below on iPhone 17 Pro Max Simulator. Scroll the text down until you see “Header 2”. Place the text cursor after “# “. Press the arrow down key twice to move the cursor two lines down. The cursor moves to the top of the view instead. Continuing to press the arrow keys up and down results in the cursor sometimes moving as expected, other times jumping around wildly. Does anyone know a workaround? I created FB22382453. class TextView: UITextView, UITextViewDelegate { override func awakeFromNib() { let _ = layoutManager delegate = self let header = textAttributes(fontSize: 30) let body = textAttributes(fontSize: 15) let string = NSMutableAttributedString(string: String(repeating: "a", count: 2681) + "\n", attributes: body) string.append(NSAttributedString(string: """ # Header 1 """, attributes: header)) string.append(NSMutableAttributedString(string: String(repeating: "a", count: 5198) + "\n", attributes: body)) string.append(NSAttributedString(string: """ # Header 2 """, attributes: header)) string.append(NSMutableAttributedString(string: String(repeating: "a", count: 7048) + "\n", attributes: body)) textStorage.setAttributedString(string) } func textViewDidChangeSelection(_ textView: UITextView) { typingAttributes = textStorage.attributes(at: selectedRange.location - 1, effectiveRange: nil) } private func textAttributes(fontSize: Double) -> [NSAttributedString.Key: Any] { var textAttributes = [NSAttributedString.Key: Any]() textAttributes[.font] = UIFont(name: "Courier", size: fontSize) let paragraphStyle = NSMutableParagraphStyle() paragraphStyle.minimumLineHeight = round(fontSize * 1.3) paragraphStyle.maximumLineHeight = paragraphStyle.minimumLineHeight textAttributes[.paragraphStyle] = paragraphStyle return textAttributes } }
Topic: UI Frameworks SubTopic: UIKit Tags:
0
0
86
3d
PDFView left-anchors to window edge instead of centering between sidebar and inspector (macOS Tahoe)
I'm building a document viewer on macOS Tahoe with a 3-column NSSplitViewController (sidebar | detail | inspector), trying to replicate how Preview displays PDFs with the page centered in the visible gap between the panels, with content bleeding under them when panning or zooming. I'm using the approach from Build an AppKit app with the new design (WWDC25): detailItem.automaticallyAdjustsSafeAreaInsets = true safeAreaInsets reports the correct values (e.g. left: 208, right: 240), and the frame does extend under both panels. But PDFView with autoScales = true anchors the page to the left edge of the window instead of centering it in the visible gap between the sidebar and inspector. I can get the page to center correctly by constraining PDFView to view.safeAreaLayoutGuide, but then content no longer extends under the panels when panning or zooming, which defeats the whole purpose. What's the correct way to center PDFView content within the visible gap while keeping the frame full-width so content bleeds under the panels? I've attached pictures of how Preview does it.
Topic: UI Frameworks SubTopic: AppKit
0
0
61
4d
UIScrollView Fast Scrolling have it scroll to the beginning when i press dpad to left while vertical scrolling
I'm triaging the issue with the fast scrolling on UIScrollView and I'm really upset how little to no info this component is on the internet. Like i disabled scrolling and yet after holding the dpad down to scroll downward eventually the fast scroll mechanism is used. The issue I have is that I have a setup where the scrollview scrolling is disabled and whenever cells are focused it'll scroll to the cell's position for that cells to focused on top left side of the scrollview. I start off with the cell placed at position x of 1000. I scroll down enough to enable fast scrolling. While fast scrolling vertically, i press left a couple of time and it somewhat scroll horizontally. Actual scrollView index is suddenly placed to x:0 instead of let say x:950-1000 Expected should be scrolled to the left of cell at position x 1000. Attached the stack trace and the log showcasing it and run it on simulator tvos 26.2. Initial properties of the scrollview we set up scroll = [UIScrollView new]; scroll.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever; scroll.automaticallyAdjustsScrollIndicatorInsets = false; [scroll setDirectionalLockEnabled:TRUE]; [scroll setContentInset:UIEdgeInsetsMake(0, 0, 0, 0)]; scroll.bounces = FALSE; scroll.delaysContentTouches = FALSE; scroll.showsVerticalScrollIndicator = FALSE; scroll.showsHorizontalScrollIndicator = FALSE; The plan for me at least is to somehow disable the horizontal scrolling interaction of it when fast scrolling is enabled, without accessing the private components of it.
0
0
56
4d
Scene resizing on iPad breaks UIPageViewController's setViewControllers
The following is verbatim of a feedback report (FB22367951) I submitted, shared here as someone else might be interested to see it. I have reproduced this bug on iPadOS 26.3.1 (a) and 26.4. During scene resizing on iPad, UIPageViewController's setViewControllers method fails to do its work. The navigation starts and for a brief moment you can see the new view controller coming from the expected direction, but shortly after it fails and stays on the same [current] view controller. It doesn't even call the completion handler when it fails. When the navigation succeeds (due to not resizing a scene during the navigation) after previously failing at least once, the completion handler is sometimes called more than once. I have created a demo project, which I have pushed to this repo: https://github.com/galijot/SceneResize-Breaks-UIPageViewController I have also attached a zip of the project to this report.
0
0
36
4d
MapKit in SwiftUI
Anyone worked with MapKit's MapCameraPosition in SwiftUI? I'm building a navigation app and ran into a limitation I can't find a clean solution for when using .userLocation(followsHeading: true) MapKit takes full control of the camera, smooth heading tracking, follows the user automatically. Perfect. But there's no way to set a custom pitch (tilt) on it. The only initializer available is... .userLocation(followsHeading: true, fallback: .automatic) No pitch, no distance parameters.... The workaround I found is setting .camera(MapCamera(..., pitch: 60)) first, waiting 200ms, then switching to .userLocation(followsHeading: true), MapKit inherits the pitch from the rendered camera state before handing off to user tracking.... It works, but it's clearly exploiting an undocumented behaviour in MapKit's state machine rather than a proper API Has anyone found a cleaner way to achieve this? Or is UIViewRepresentable wrapping MKMapView the only proper solution? It would be awesome to have something like this cameraPosition = .userLocation( followsHeading: true, pitch: 60, distance: 800, fallback: .automatic )
1
0
120
5d
NavigationLink selection in DisclosureGroup not working with .draggable modifier
NavigationLink selection in DisclosureGroup not working with .draggable modifier This was recently also posted here: https://stackoverflow.com/questions/79914290/ I am playing around with a tree data structure with folders and entries.I would like to add dragging of entries and folders between folders, using .draggable and dropDestination. In my current code, dragging works, but selection of entries no longer works, except if I click outside of the Text If I comment out .draggable(subfolder.name) in func FolderRow(), selection works as expected. How can I make sure both selection and drag and drop works for both folders and entries? I also tried using Transferable and Codable, but I get the same result. Here is an MRE: import SwiftData import SwiftUI @Model final class Folder { @Attribute(.unique) var name: String // Parent var parentFolder: Folder? // Child folders @Relationship(deleteRule: .cascade, inverse: \Folder.parentFolder) var subfolders: [Folder] = [] // Leaf entries @Relationship(deleteRule: .cascade, inverse: \Entry.folder) var entries: [Entry] = [] init(name: String, parentFolder: Folder? = nil) { self.name = name self.parentFolder = parentFolder } } @Model final class Entry { @Attribute(.unique) var name: String var detail: String var folder: Folder? // recursive relationship init(name: String, detail: String) { self.name = name self.detail = detail } } @main struct TestMacApp: App { var body: some Scene { WindowGroup { SidebarView() .modelContainer(for: Folder.self) } } } struct SidebarView: View { @Environment(\.modelContext) private var context @Query(filter: #Predicate<Folder> { $0.parentFolder == nil }) private var rootFolders: [Folder] var body: some View { NavigationSplitView { List { ForEach(rootFolders) { folder in FolderRow(folder: folder) .draggable(folder.name) } } } detail: { Text("detail") } .onAppear { seed() } } } struct FolderRow: View { @Environment(\.modelContext) private var context var folder: Folder @State private var isExpanded: Bool = true var body: some View { DisclosureGroup(isExpanded: $isExpanded) { // Subfolders ForEach(folder.subfolders) { subfolder in FolderRow(folder: subfolder) .draggable(subfolder.name) // disabling this line fixes the selection } // Entries (leaf nodes) ForEach(folder.entries) { entry in NavigationLink(destination: EntryDetail(entry: entry)) { EntryRow(entry: entry) } .draggable(entry.name) } } label: { Label(folder.name, systemImage: "folder") } .dropDestination(for: String.self) { names, _ in return handleDrop(of: names) } } } struct EntryRow: View { var entry: Entry var body: some View { Text(entry.name) } } struct EntryDetail: View { var entry: Entry var body: some View { Text(entry.detail) } } extension FolderRow { private func handleDrop(of names: [String]) -> Bool { do { for name in names { if let droppedEntry = try context.fetchFilteredModel(filter: #Predicate<Entry> { x in x.name == name }) { droppedEntry.folder = folder print("dropped \(droppedEntry.name) on \(folder.name)") } else if let droppedFolder = try context.fetchFilteredModel(filter: #Predicate<Folder> { x in x.name == name }) { if droppedFolder.parentFolder != nil && droppedFolder != folder { droppedFolder.parentFolder = folder print("dropped \(droppedFolder.name) on \(folder.name)") } } } return true } catch { debugPrint(error.localizedDescription) return false } } } extension SidebarView { private func seed() { do { // delete current models for folder: Folder in try context.fetchAllModels() { context.delete(folder) } try context.save() let rootFolder = Folder(name: "Root") let entry1 = Entry(name: "One", detail: "Detail One") let entry2 = Entry(name: "Two", detail: "Detail Two") rootFolder.entries.append(contentsOf: [entry1, entry2]) let subFolder1 = Folder(name: "Sub1", parentFolder: rootFolder) let entry3 = Entry(name: "Three", detail: "Detail Three") let entry4 = Entry(name: "Four", detail: "Detail Four") subFolder1.entries.append(contentsOf: [entry3, entry4]) let subFolder2 = Folder(name: "Sub2", parentFolder: rootFolder) let entry5 = Entry(name: "Five", detail: "Detail Five") let entry6 = Entry(name: "Six", detail: "Detail Six") subFolder2.entries.append(contentsOf: [entry5, entry6]) context.insert(rootFolder) } catch { debugPrint(error) } } } extension ModelContext { // convenience methods func fetchAllModels<M>() throws -> [M] where M: PersistentModel { let fetchDescriptor = FetchDescriptor<M>() return try fetch(fetchDescriptor) } func fetchFilteredModels<M>(filter: Predicate<M>) throws -> [M] where M: PersistentModel { let fetchDescriptor = FetchDescriptor<M>(predicate: filter) return try fetch(fetchDescriptor) } func fetchFilteredModel<M>(filter: Predicate<M>) throws -> M? where M: PersistentModel { return try fetchFilteredModels(filter: filter).first } }
Topic: UI Frameworks SubTopic: SwiftUI
1
0
170
4d
Left navigation bar items become invisible after rotating device and presenting detail view in split view
A user of my app, whose main view is a split view, reported an issue which causes the left navigation bar items to disappear without apparent reason if they rotate the device and later show the detail view, preventing them from using the back button to show the root view again. Am I doing something wrong or is it a bug? I can reproduce the issue with the following steps: Create a new document-based iOS app (as it uses scenes by default, as opposed to a regular app). Paste the code below. In the target build settings, delete "Launch Screen Interface File Base Name" and set "Launch Screen (Generation)" to YES. Without this step, for some reason, the issue doesn't happen. Launch the app in iPhone Simulator. Tap the top left button to show the root view, then the “detail” button to show the detail view. The left navigation bar button is still visible. Rotate the Simulator window right, then left again. Tap the top left button to show the root view, then the “detail” button to show the detail view. Now the left navigation bar button is invisible. Rotating the device right and left again solves the issue. I filed FB22363118. class SceneDelegate: UIResponder, UIWindowSceneDelegate { var window: UIWindow? func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) { window = UIWindow(windowScene: scene as! UIWindowScene) let split = SplitViewController() window!.rootViewController = split window!.makeKeyAndVisible() split.showDetail() } } class SplitViewController: UISplitViewController, UISplitViewControllerDelegate { var detailNavigationViewController: UINavigationController! init() { super.init(nibName: nil, bundle: nil) detailNavigationViewController = UINavigationController(rootViewController: DetailViewController()) viewControllers = [UINavigationController(rootViewController: RootViewController())] } required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } func showDetail() { showDetailViewController(detailNavigationViewController, sender: nil) } func showRoot() { (viewControllers.first as? UINavigationController)?.popViewController(animated: true) } } class RootViewController: UIViewController { override func loadView() { navigationItem.title = "root" let button = UIButton(primaryAction: UIAction(handler: { [self] _ in (splitViewController as! SplitViewController).showDetail() })) button.setTitle("detail", for: .normal) view = button } } class DetailViewController: UIViewController { override func loadView() { navigationItem.title = "detail" view = UIView() registerForTraitChanges([UITraitHorizontalSizeClass.self]) { (self: Self, previousTraitCollection) in if previousTraitCollection.horizontalSizeClass != self.traitCollection.horizontalSizeClass { self.updateBarButtons() } } updateBarButtons() } private func updateBarButtons() { navigationItem.leftBarButtonItem = UIBarButtonItem(primaryAction: UIAction(image: UIImage(systemName: "sidebar.leading")) { [self] _ in (self.splitViewController as! SplitViewController).showRoot() }) navigationItem.rightBarButtonItem = UIBarButtonItem(title: "right") } }
Topic: UI Frameworks SubTopic: UIKit Tags:
0
0
53
5d
A Summary of the WWDC25 Group Lab - UI Frameworks
At WWDC25 we launched a new type of Lab event for the developer community - Group Labs. A Group Lab is a panel Q&A designed for a large audience of developers. Group Labs are a unique opportunity for the community to submit questions directly to a panel of Apple engineers and designers. Here are the highlights from the WWDC25 Group Lab for UI Frameworks. How would you recommend developers start adopting the new design? Start by focusing on the foundational structural elements of your application, working from the "top down" or "bottom up" based on your application's hierarchy. These structural changes, like edge-to-edge content and updated navigation and controls, often require corresponding code modifications. As a first step, recompile your application with the new SDK to see what updates are automatically applied, especially if you've been using standard controls. Then, carefully analyze where the new design elements can be applied to your UI, paying particular attention to custom controls or UI that could benefit from a refresh. Address the large structural items first then focus on smaller details is recommended. Will we need to migrate our UI code to Swift and SwiftUI to adopt the new design? No, you will not need to migrate your UI code to Swift and SwiftUI to adopt the new design. The UI frameworks fully support the new design, allowing you to migrate your app with as little effort as possible, especially if you've been using standard controls. The goal is to make it easy to adopt the new design, regardless of your current UI framework, to achieve a cohesive look across the operating system. What was the reason for choosing Liquid Glass over frosted glass, as used in visionOS? The choice of Liquid Glass was driven by the desire to bring content to life. The see-through nature of Liquid Glass enhances this effect. The appearance of Liquid Glass adapts based on its size; larger glass elements look more frosted, which aligns with the design of visionOS, where everything feels larger and benefits from the frosted look. What are best practices for apps that use customized navigation bars? The new design emphasizes behavior and transitions as much as static appearance. Consider whether you truly need a custom navigation bar, or if the system-provided controls can meet your needs. Explore new APIs for subtitles and custom views in navigation bars, designed to support common use cases. If you still require a custom solution, ensure you're respecting safe areas using APIs like SwiftUI's safeAreaInset. When working with Liquid Glass, group related buttons in shared containers to maintain design consistency. Finally, mark glass containers as interactive. For branding, instead of coloring the navigation bar directly, consider incorporating branding colors into the content area behind the Liquid Glass controls. This creates a dynamic effect where the color is visible through the glass and moves with the content as the user scrolls. I want to know why new UI Framework APIs aren’t backward compatible, specifically in SwiftUI? It leads to code with lots of if-else statements. Existing APIs have been updated to work with the new design where possible, ensuring that apps using those APIs will adopt the new design and function on both older and newer operating systems. However, new APIs often depend on deep integration across the framework and graphics stack, making backward compatibility impractical. When using these new APIs, it's important to consider how they fit within the context of the latest OS. The use of if-else statements allows you to maintain compatibility with older systems while taking full advantage of the new APIs and design features on newer systems. If you are using new APIs, it likely means you are implementing something very specific to the new design language. Using conditional code allows you to intentionally create different code paths for the new design versus older operating systems. Prefer to use if #available where appropriate to intentionally adopt new design elements. Are there any Liquid Glass materials in iOS or macOS that are only available as part of dedicated components? Or are all those materials available through new UIKit and AppKit views? Yes, some variations of the Liquid Glass material are exclusively available through dedicated components like sliders, segmented controls, and tab bars. However, the "regular" and "clear" glass materials should satisfy most application requirements. If you encounter situations where these options are insufficient, please file feedback. If I were to create an app today, how should I design it to make it future proof using Liquid Glass? The best approach to future-proof your app is to utilize standard system controls and design your UI to align with the standard system look and feel. Using the framework-provided declarative API generally leads to easier adoption of future design changes, as you're expressing intent rather than specifying pixel-perfect visuals. Pay close attention to the design sessions offered this year, which cover the design motivation behind the Liquid Glass material and best practices for its use. Is it possible to implement your own sidebar on macOS without NSSplitViewController, but still provide the Liquid Glass appearance? While technically possible to create a custom sidebar that approximates the Liquid Glass appearance without using NSSplitViewController, it is not recommended. The system implementation of the sidebar involves significant unseen complexity, including interlayering with scroll edge effects and fullscreen behaviors. NSSplitViewController provides the necessary level of abstraction for the framework to handle these details correctly. Regarding the SceneDelagate and scene based life-cycle, I would like to confirm that AppDelegate is not going away. Also if the above is a correct understanding, is there any advice as to what should, and should not, be moved to the SceneDelegate? UIApplicationDelegate is not going away and still serves a purpose for application-level interactions with the system and managing scenes at a higher level. Move code related to your app's scene or UI into the UISceneDelegate. Remember that adopting scenes doesn't necessarily mean supporting multiple scenes; an app can be scene-based but still support only one scene. Refer to the tech note Migrating to the UIKit scene-based life cycle and the Make your UIKit app more flexible WWDC25 session for more information.
Topic: UI Frameworks SubTopic: General
Replies
0
Boosts
0
Views
884
Activity
Jun ’25
iOS 26 TabBar Remove Selected Capsule
I have subclassed UITabBar and created a custom look and feel for it. On iOS 18, the tab bar appears as expected. On iOS 26, however, a default Liquid Glass-style capsule selection indicator appears behind the selected tab item. I tried using UITabBarAppearance, including selectionIndicatorTintColor = .clear and selectionIndicatorImage = nil / empty image, but the capsule-style selected background still appears. Is this selection treatment part of the new default system rendering in iOS 26, and if so, is there any supported way to remove or disable it while still using UITabBar?
Topic: UI Frameworks SubTopic: UIKit Tags:
Replies
1
Boosts
0
Views
30
Activity
6h
Update FreeType to support the new Chinese font format
Beginning with macOS Sonoma, Apple introduced a novel font format for rendering Chinese text. Apps that use third-party libraries for text rendering continued to function, primarily without disruption, owing to some workarounds provided by the operating system. FreeType, one of the most widely used cross-platform libraries for text rendering, now supports this new format. Apps that use this library, regardless of whether they encountered issues with Chinese text or not, should update to the latest FreeType source from their git repository (https://gitlab.freedesktop.org/freetype/freetype), as this support is not yet available in a tagged release. Updating ensures that apps operate optimally with Chinese text as well as any other language that uses this new format. Because this support calls into Apple APIs that Apple introduced in macOS 15.4, iOS 18.4, and aligned watchOS, tvOS, and visionOS releases, set the deployment target when building FreeType to match that of your own app. This ensures that the new API calls fail gracefully on older OS versions rather than causing your app to crash on systems where those APIs are not available.
Replies
0
Boosts
0
Views
82
Activity
1d
Password autofill not respecting contentType of NSSecureTextField
We have a Mac app the allows customers to create a user account in our system. However, we have found that on the 'create account' screen, the system's password autofill is popping up for the "New Password" field. We don't want this, because they need to enter a new password, not pull one from the Passwords app. I built a test project with a basic UI and explicitly set the content type to None in the XIB. However, I can see when I put focus on the "New Password" NSSecureTextField, the system shows the passwords autofill popup. How can I explicitly suppress this on a per text field basis? (We are developing on macOS 26.3 right now with Xcode 26.3)
Topic: UI Frameworks SubTopic: AppKit
Replies
0
Boosts
0
Views
17
Activity
1d
DiffableDataSource hangs on apply
About a year ago, I developed and released an app on the App Store (I believe it was running on the Sequoia SDK at the time), and everything was working fine. I’m now revisiting the project using the newer Tahoe SDK, and I’m running into an issue with DiffableDataSource. Specifically, the app hangs and CPU usage spikes to 100% when applying snapshots. Has anyone experienced similar issues after upgrading to newer SDKs? Are there any recent changes or pitfalls with DiffableDataSource (e.g., threading, Hashable requirements, or snapshot handling) that I should be aware of? Any insights or suggestions would be greatly appreciated. extension Section { enum Identifier: Int, CaseIterable { case main } enum Item: Hashable { case file(FileViewData) } } struct FileViewData: Equatable, Hashable, Identifiable { let id: String let name: String var accessoryViewData: KTFDownloadAccessoryViewData init( id: String, name: String, accessoryViewData: KTFDownloadAccessoryViewData = .nothing ) { self.id = id self.name = name self.accessoryViewData = accessoryViewData } } public enum KTFDownloadAccessoryViewData: Equatable, Hashable { case nothing case selected(SelectedState) case completed public enum SelectedState: Equatable, Hashable { case nothing case waiting case downloading(Double) } } When I changed FileViewData as below, no hangs but item appearance doesn't change of course. struct FileViewData: Equatable, Hashable, Identifiable { let id: String let name: String var accessoryViewData: KTFDownloadAccessoryViewData init( id: String, name: String, accessoryViewData: KTFDownloadAccessoryViewData = .nothing ) { self.id = id self.name = name self.accessoryViewData = accessoryViewData } func hash(into hasher: inout Hasher) { hasher.combine(id) } static func == (lhs: FileViewData, rhs: FileViewData) -> Bool { return lhs.id == rhs.id } }
Topic: UI Frameworks SubTopic: UIKit Tags:
Replies
1
Boosts
0
Views
38
Activity
1d
NSDocument "saveToURL:ofType:..." is using outdated file type
These days I've observed a strange behavior in my document-based app on macOS: Its NSDocument class implementation is overwriting "saveToURL:ofType:forSaveOperation:completionHandler:", performing some additional checks and calling super by passing the original parameters. As my app is supporting various file formats for writing (and exporting those UTIs) the user can open a file in one format and save it to another. NSDocument is calling the mentioned methods implicitly after completing the "Save as..." dialog. If this happens, the passed-on fileType is still the one of format #1, although the file is saved with the file name extension of format #2. This hick-up is not directly obvious to the user. But if the file is re-saved (e.g. after modifications), Cocoa is trying to extend the sandbox for the URL of type #1, and fails with the following error message at the Xcode console: -[STBDocument saveToURL:ofType:forSaveOperation:completionHandler:] [Line 521] typeName: com.janome.jef -[STBDocument saveToURL:ofType:forSaveOperation:completionHandler:] [Line 523] targetTypeUTI: com.tajima.dst NSFileSandboxingRequestRelatedItemExtension: Failed to issue extension for /Users/matthias/Desktop/Ohne Titel.jef because: Error Domain=NSPOSIXErrorDomain Code=3 "No such process" -[NSFileCoordinator itemAtURL:willMoveToURL:] could not get a sandbox extension. oldURL: file:///Users/matthias/Desktop/Ohne%20Titel.dst, newURL: file:///Users/matthias/Desktop/Ohne%20Titel.jef I'm currently fixing this issue by determining the UTType for the new file name extension and passing it to super. Unfortunately I have no idea how long this issue was already present, and cannot replicate it with a sample app based on Apple's Xcode 26 template (too many differences to my >15 years old app) - so I won't file a bug report. Take this post just for information in case someone else is facing a similar situation...
Replies
0
Boosts
0
Views
36
Activity
1d
iOS26的TabBar是否支持lottie动画?
iOS26的TabBar是否支持lottie动画?
Topic: UI Frameworks SubTopic: UIKit
Replies
1
Boosts
0
Views
30
Activity
12h
There is a problem using UIImagePickerController
When taking a photo with UIImagePickerController, the text in "Use Photo" shifts. What could be the reason for this?
Topic: UI Frameworks SubTopic: General
Replies
0
Boosts
0
Views
10
Activity
1d
Initial presentation of popover hangs when shown from a button in the toolbar
I have a simple reproducer here: struct ContentView: View { @State private var isOn = false @State private var isPresented = false var body: some View { NavigationStack { Color.blue .toolbar { ToolbarItem(placement: .topBarTrailing) { Button("Press here") { isPresented = true } .popover(isPresented: $isPresented) { Color.green .frame(idealWidth: 400, idealHeight: 500) .presentationCompactAdaptation(.popover) } } } } } } When I tap on the button in the toolbar you can see there is a hang then the popover shows. Then every time after there is no longer a hang so this seems like a bug. Any ideas? I'm using Xcode 26.3 and a iPad Pro 13-inch (M5) (26.4) simulator.
Replies
1
Boosts
3
Views
83
Activity
5h
Window size of iOS app running on Mac
I need constraint the window size for an iOS app running on Mac. That's easy for a MacApp, using self.window?.minSize.width = 450 self.window?.maxSize.width = 450 or use func windowDidResize(_ notification: Notification) { } but how to achieve it in UIKit ?
Replies
3
Boosts
0
Views
150
Activity
1d
X button disappeared on iPadOS 26.4 in MFMailComposeViewController
I’m using MFMailComposeViewController to send emails from my app. Since updating to iPadOS 26.4, there is no way to cancel the mail composer because the “X” button in the top-left corner has disappeared. On iPhone with iOS 26.4, everything still seems to work as expected. Is this a known issue, or am I missing something? Has anyone else experienced this, or found a workaround?
Topic: UI Frameworks SubTopic: UIKit
Replies
2
Boosts
0
Views
131
Activity
2d
NSTextAttachment.character symbol suddenly not available anymore resulting in compiler error
I published the latest update of my AppKit app in September with macOS 26.0. I just wanted to create a new update, but compiling on macOS 26.4 now fails because of the symbol NSTextAttachment.character which is referenced in my code. The error is Type 'NSTextAttachment' has no member 'character' I've never experienced before that a symbol suddenly is not available anymore without even a deprecation notice from one OS release to the next, let alone a minor release. Is this a bug in macOS or Xcode, or should I start worrying about symbols becoming unavailable anytime?
Replies
2
Boosts
0
Views
183
Activity
1d
Potentially Unfair Limitation for Third-Party Keyboard Developers
When developing a custom keyboard on iOS, even after enabling Full Access (RequestsOpenAccess = true), it is still not possible to record audio — the recording simply does not start. This is despite the fact that: the user is explicitly warned the user provides informed consent by enabling Full Access According to Apple’s documentation: https://developer.apple.com/documentation/uikit/configuring-open-access-for-a-custom-keyboard “However, with RequestsOpenAccess set to true, the keyboard has all the capabilities in the preceding list.” At the same time, the preceding list includes: “No access to microphone and speaker” This creates ambiguity. The wording suggests that enabling Full Access should lift prior restrictions, yet in practice, microphone access remains unavailable to third-party keyboards. Why this is concerning With Full Access enabled, a keyboard already has: network access the ability to transmit user input From a privacy standpoint, this is already highly sensitive. Preventing microphone access while allowing these capabilities appears inconsistent. Meanwhile, Apple’s own system keyboard supports voice dictation, which creates a functional gap between first-party and third-party keyboards. Competition perspective This raises a broader question about equal access to platform capabilities. Restricting third-party keyboards from using the microphone — while first-party solutions can — may be seen as: unequal treatment of developers a limitation of competition in input methods Such differences are increasingly scrutinized under EU regulations like the Digital Markets Act and Article 102 TFEU, which emphasize fair access to platform features and prohibit self-preferencing by dominant platforms. Request for clarification Is microphone access intentionally restricted for all third-party keyboards, even with Full Access enabled? If so, what is the technical or policy justification? Are there plans to provide a secure and user-consented way to enable audio input for custom keyboards? Clarification on this would help developers better understand platform limitations and design decisions.
Replies
0
Boosts
0
Views
62
Activity
2d
UITextView cursor sometimes jumps up when pressing arrow down key and setting typingAttributes
My app uses TextKit 1 and unfortunately still cannot migrate to TextKit 2 because of some bugs (for instance in FB17103305 I show how NSTextView.shouldDrawInsertionPoint has no effect, but I opened that feedback exactly one year ago and it still has no answer). Unfortunately TextKit 1 has another bug which causes the text cursor to jump unpredictably up or down when pressing the arrow keys and setting UITextView.typingAttributes. Run the code below on iPhone 17 Pro Max Simulator. Scroll the text down until you see “Header 2”. Place the text cursor after “# “. Press the arrow down key twice to move the cursor two lines down. The cursor moves to the top of the view instead. Continuing to press the arrow keys up and down results in the cursor sometimes moving as expected, other times jumping around wildly. Does anyone know a workaround? I created FB22382453. class TextView: UITextView, UITextViewDelegate { override func awakeFromNib() { let _ = layoutManager delegate = self let header = textAttributes(fontSize: 30) let body = textAttributes(fontSize: 15) let string = NSMutableAttributedString(string: String(repeating: "a", count: 2681) + "\n", attributes: body) string.append(NSAttributedString(string: """ # Header 1 """, attributes: header)) string.append(NSMutableAttributedString(string: String(repeating: "a", count: 5198) + "\n", attributes: body)) string.append(NSAttributedString(string: """ # Header 2 """, attributes: header)) string.append(NSMutableAttributedString(string: String(repeating: "a", count: 7048) + "\n", attributes: body)) textStorage.setAttributedString(string) } func textViewDidChangeSelection(_ textView: UITextView) { typingAttributes = textStorage.attributes(at: selectedRange.location - 1, effectiveRange: nil) } private func textAttributes(fontSize: Double) -> [NSAttributedString.Key: Any] { var textAttributes = [NSAttributedString.Key: Any]() textAttributes[.font] = UIFont(name: "Courier", size: fontSize) let paragraphStyle = NSMutableParagraphStyle() paragraphStyle.minimumLineHeight = round(fontSize * 1.3) paragraphStyle.maximumLineHeight = paragraphStyle.minimumLineHeight textAttributes[.paragraphStyle] = paragraphStyle return textAttributes } }
Topic: UI Frameworks SubTopic: UIKit Tags:
Replies
0
Boosts
0
Views
86
Activity
3d
PDFView left-anchors to window edge instead of centering between sidebar and inspector (macOS Tahoe)
I'm building a document viewer on macOS Tahoe with a 3-column NSSplitViewController (sidebar | detail | inspector), trying to replicate how Preview displays PDFs with the page centered in the visible gap between the panels, with content bleeding under them when panning or zooming. I'm using the approach from Build an AppKit app with the new design (WWDC25): detailItem.automaticallyAdjustsSafeAreaInsets = true safeAreaInsets reports the correct values (e.g. left: 208, right: 240), and the frame does extend under both panels. But PDFView with autoScales = true anchors the page to the left edge of the window instead of centering it in the visible gap between the sidebar and inspector. I can get the page to center correctly by constraining PDFView to view.safeAreaLayoutGuide, but then content no longer extends under the panels when panning or zooming, which defeats the whole purpose. What's the correct way to center PDFView content within the visible gap while keeping the frame full-width so content bleeds under the panels? I've attached pictures of how Preview does it.
Topic: UI Frameworks SubTopic: AppKit
Replies
0
Boosts
0
Views
61
Activity
4d
UIScrollView Fast Scrolling have it scroll to the beginning when i press dpad to left while vertical scrolling
I'm triaging the issue with the fast scrolling on UIScrollView and I'm really upset how little to no info this component is on the internet. Like i disabled scrolling and yet after holding the dpad down to scroll downward eventually the fast scroll mechanism is used. The issue I have is that I have a setup where the scrollview scrolling is disabled and whenever cells are focused it'll scroll to the cell's position for that cells to focused on top left side of the scrollview. I start off with the cell placed at position x of 1000. I scroll down enough to enable fast scrolling. While fast scrolling vertically, i press left a couple of time and it somewhat scroll horizontally. Actual scrollView index is suddenly placed to x:0 instead of let say x:950-1000 Expected should be scrolled to the left of cell at position x 1000. Attached the stack trace and the log showcasing it and run it on simulator tvos 26.2. Initial properties of the scrollview we set up scroll = [UIScrollView new]; scroll.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever; scroll.automaticallyAdjustsScrollIndicatorInsets = false; [scroll setDirectionalLockEnabled:TRUE]; [scroll setContentInset:UIEdgeInsetsMake(0, 0, 0, 0)]; scroll.bounces = FALSE; scroll.delaysContentTouches = FALSE; scroll.showsVerticalScrollIndicator = FALSE; scroll.showsHorizontalScrollIndicator = FALSE; The plan for me at least is to somehow disable the horizontal scrolling interaction of it when fast scrolling is enabled, without accessing the private components of it.
Replies
0
Boosts
0
Views
56
Activity
4d
Scene resizing on iPad breaks UIPageViewController's setViewControllers
The following is verbatim of a feedback report (FB22367951) I submitted, shared here as someone else might be interested to see it. I have reproduced this bug on iPadOS 26.3.1 (a) and 26.4. During scene resizing on iPad, UIPageViewController's setViewControllers method fails to do its work. The navigation starts and for a brief moment you can see the new view controller coming from the expected direction, but shortly after it fails and stays on the same [current] view controller. It doesn't even call the completion handler when it fails. When the navigation succeeds (due to not resizing a scene during the navigation) after previously failing at least once, the completion handler is sometimes called more than once. I have created a demo project, which I have pushed to this repo: https://github.com/galijot/SceneResize-Breaks-UIPageViewController I have also attached a zip of the project to this report.
Replies
0
Boosts
0
Views
36
Activity
4d
MapKit in SwiftUI
Anyone worked with MapKit's MapCameraPosition in SwiftUI? I'm building a navigation app and ran into a limitation I can't find a clean solution for when using .userLocation(followsHeading: true) MapKit takes full control of the camera, smooth heading tracking, follows the user automatically. Perfect. But there's no way to set a custom pitch (tilt) on it. The only initializer available is... .userLocation(followsHeading: true, fallback: .automatic) No pitch, no distance parameters.... The workaround I found is setting .camera(MapCamera(..., pitch: 60)) first, waiting 200ms, then switching to .userLocation(followsHeading: true), MapKit inherits the pitch from the rendered camera state before handing off to user tracking.... It works, but it's clearly exploiting an undocumented behaviour in MapKit's state machine rather than a proper API Has anyone found a cleaner way to achieve this? Or is UIViewRepresentable wrapping MKMapView the only proper solution? It would be awesome to have something like this cameraPosition = .userLocation( followsHeading: true, pitch: 60, distance: 800, fallback: .automatic )
Replies
1
Boosts
0
Views
120
Activity
5d
NavigationLink selection in DisclosureGroup not working with .draggable modifier
NavigationLink selection in DisclosureGroup not working with .draggable modifier This was recently also posted here: https://stackoverflow.com/questions/79914290/ I am playing around with a tree data structure with folders and entries.I would like to add dragging of entries and folders between folders, using .draggable and dropDestination. In my current code, dragging works, but selection of entries no longer works, except if I click outside of the Text If I comment out .draggable(subfolder.name) in func FolderRow(), selection works as expected. How can I make sure both selection and drag and drop works for both folders and entries? I also tried using Transferable and Codable, but I get the same result. Here is an MRE: import SwiftData import SwiftUI @Model final class Folder { @Attribute(.unique) var name: String // Parent var parentFolder: Folder? // Child folders @Relationship(deleteRule: .cascade, inverse: \Folder.parentFolder) var subfolders: [Folder] = [] // Leaf entries @Relationship(deleteRule: .cascade, inverse: \Entry.folder) var entries: [Entry] = [] init(name: String, parentFolder: Folder? = nil) { self.name = name self.parentFolder = parentFolder } } @Model final class Entry { @Attribute(.unique) var name: String var detail: String var folder: Folder? // recursive relationship init(name: String, detail: String) { self.name = name self.detail = detail } } @main struct TestMacApp: App { var body: some Scene { WindowGroup { SidebarView() .modelContainer(for: Folder.self) } } } struct SidebarView: View { @Environment(\.modelContext) private var context @Query(filter: #Predicate<Folder> { $0.parentFolder == nil }) private var rootFolders: [Folder] var body: some View { NavigationSplitView { List { ForEach(rootFolders) { folder in FolderRow(folder: folder) .draggable(folder.name) } } } detail: { Text("detail") } .onAppear { seed() } } } struct FolderRow: View { @Environment(\.modelContext) private var context var folder: Folder @State private var isExpanded: Bool = true var body: some View { DisclosureGroup(isExpanded: $isExpanded) { // Subfolders ForEach(folder.subfolders) { subfolder in FolderRow(folder: subfolder) .draggable(subfolder.name) // disabling this line fixes the selection } // Entries (leaf nodes) ForEach(folder.entries) { entry in NavigationLink(destination: EntryDetail(entry: entry)) { EntryRow(entry: entry) } .draggable(entry.name) } } label: { Label(folder.name, systemImage: "folder") } .dropDestination(for: String.self) { names, _ in return handleDrop(of: names) } } } struct EntryRow: View { var entry: Entry var body: some View { Text(entry.name) } } struct EntryDetail: View { var entry: Entry var body: some View { Text(entry.detail) } } extension FolderRow { private func handleDrop(of names: [String]) -> Bool { do { for name in names { if let droppedEntry = try context.fetchFilteredModel(filter: #Predicate<Entry> { x in x.name == name }) { droppedEntry.folder = folder print("dropped \(droppedEntry.name) on \(folder.name)") } else if let droppedFolder = try context.fetchFilteredModel(filter: #Predicate<Folder> { x in x.name == name }) { if droppedFolder.parentFolder != nil && droppedFolder != folder { droppedFolder.parentFolder = folder print("dropped \(droppedFolder.name) on \(folder.name)") } } } return true } catch { debugPrint(error.localizedDescription) return false } } } extension SidebarView { private func seed() { do { // delete current models for folder: Folder in try context.fetchAllModels() { context.delete(folder) } try context.save() let rootFolder = Folder(name: "Root") let entry1 = Entry(name: "One", detail: "Detail One") let entry2 = Entry(name: "Two", detail: "Detail Two") rootFolder.entries.append(contentsOf: [entry1, entry2]) let subFolder1 = Folder(name: "Sub1", parentFolder: rootFolder) let entry3 = Entry(name: "Three", detail: "Detail Three") let entry4 = Entry(name: "Four", detail: "Detail Four") subFolder1.entries.append(contentsOf: [entry3, entry4]) let subFolder2 = Folder(name: "Sub2", parentFolder: rootFolder) let entry5 = Entry(name: "Five", detail: "Detail Five") let entry6 = Entry(name: "Six", detail: "Detail Six") subFolder2.entries.append(contentsOf: [entry5, entry6]) context.insert(rootFolder) } catch { debugPrint(error) } } } extension ModelContext { // convenience methods func fetchAllModels<M>() throws -> [M] where M: PersistentModel { let fetchDescriptor = FetchDescriptor<M>() return try fetch(fetchDescriptor) } func fetchFilteredModels<M>(filter: Predicate<M>) throws -> [M] where M: PersistentModel { let fetchDescriptor = FetchDescriptor<M>(predicate: filter) return try fetch(fetchDescriptor) } func fetchFilteredModel<M>(filter: Predicate<M>) throws -> M? where M: PersistentModel { return try fetchFilteredModels(filter: filter).first } }
Topic: UI Frameworks SubTopic: SwiftUI
Replies
1
Boosts
0
Views
170
Activity
4d
Left navigation bar items become invisible after rotating device and presenting detail view in split view
A user of my app, whose main view is a split view, reported an issue which causes the left navigation bar items to disappear without apparent reason if they rotate the device and later show the detail view, preventing them from using the back button to show the root view again. Am I doing something wrong or is it a bug? I can reproduce the issue with the following steps: Create a new document-based iOS app (as it uses scenes by default, as opposed to a regular app). Paste the code below. In the target build settings, delete "Launch Screen Interface File Base Name" and set "Launch Screen (Generation)" to YES. Without this step, for some reason, the issue doesn't happen. Launch the app in iPhone Simulator. Tap the top left button to show the root view, then the “detail” button to show the detail view. The left navigation bar button is still visible. Rotate the Simulator window right, then left again. Tap the top left button to show the root view, then the “detail” button to show the detail view. Now the left navigation bar button is invisible. Rotating the device right and left again solves the issue. I filed FB22363118. class SceneDelegate: UIResponder, UIWindowSceneDelegate { var window: UIWindow? func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) { window = UIWindow(windowScene: scene as! UIWindowScene) let split = SplitViewController() window!.rootViewController = split window!.makeKeyAndVisible() split.showDetail() } } class SplitViewController: UISplitViewController, UISplitViewControllerDelegate { var detailNavigationViewController: UINavigationController! init() { super.init(nibName: nil, bundle: nil) detailNavigationViewController = UINavigationController(rootViewController: DetailViewController()) viewControllers = [UINavigationController(rootViewController: RootViewController())] } required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } func showDetail() { showDetailViewController(detailNavigationViewController, sender: nil) } func showRoot() { (viewControllers.first as? UINavigationController)?.popViewController(animated: true) } } class RootViewController: UIViewController { override func loadView() { navigationItem.title = "root" let button = UIButton(primaryAction: UIAction(handler: { [self] _ in (splitViewController as! SplitViewController).showDetail() })) button.setTitle("detail", for: .normal) view = button } } class DetailViewController: UIViewController { override func loadView() { navigationItem.title = "detail" view = UIView() registerForTraitChanges([UITraitHorizontalSizeClass.self]) { (self: Self, previousTraitCollection) in if previousTraitCollection.horizontalSizeClass != self.traitCollection.horizontalSizeClass { self.updateBarButtons() } } updateBarButtons() } private func updateBarButtons() { navigationItem.leftBarButtonItem = UIBarButtonItem(primaryAction: UIAction(image: UIImage(systemName: "sidebar.leading")) { [self] _ in (self.splitViewController as! SplitViewController).showRoot() }) navigationItem.rightBarButtonItem = UIBarButtonItem(title: "right") } }
Topic: UI Frameworks SubTopic: UIKit Tags:
Replies
0
Boosts
0
Views
53
Activity
5d