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

iOS26 - search
I have several locations in my app where the user can search. He can search within the apps content or search for content from the web to add to the app. i would like to use the tab view search box for both, but I don’t know how to do that. I currently have a tab with value search for the „web search“ and a list with .searchable for the in app content. The later one adds the search bar on top of the list. W hat’s the best way to modify this behavior?
Topic: UI Frameworks SubTopic: SwiftUI
0
0
188
Jul ’25
Live activity widget not updated locally after server update
I am using live activity in my app. Functionality is start, update & end events are started from the server. There is one interaction button added using app intent in live activity widget. That button needs to update widget ui locally using activity kit. Issue is when os receives first start event push then update ui works fine and reflecting on live activity widget but when update notification receives by os after 1 mins then action button stops updating the ui locally. Can anyone please add some suggestions to fix this.
0
0
139
May ’25
iPadOS textFormatting menu does not appeared
I have this in my swift file: CommandGroup(replacing: .textFormatting) { Toggle("Bold Text", systemImage: "bold", isOn: boldBinding) .keyboardShortcut("B") Button("Align Left", systemImage: "text.alignleft") { alignmentBinding.wrappedValue = 1 } .keyboardShortcut("[") Button("Align Center", systemImage: "text.aligncenter") { alignmentBinding.wrappedValue = 0 } .keyboardShortcut("\\") Button("Align Right", systemImage: "text.alignright") { alignmentBinding.wrappedValue = 2 } .keyboardShortcut("]") } Nothing appeared in iPadOS menu (but does appeared on Mac). Change textFormatting to textEditing does work, but appeared in a very long menu
Topic: UI Frameworks SubTopic: SwiftUI
0
0
107
Jul ’25
AppEntity with @Parameter Options Works in Shortcuts App but Not with Siri
I’m working with AppIntents and AppEntity to integrate my app’s data model into Shortcuts and Siri. In the example below, I define a custom FoodEntity and use it as a @Parameter in an AppIntent. I’m providing dynamic options for this parameter via an optionsProvider. In the Shortcuts app, everything works as expected: when the user runs the shortcut, they get a list of food options (from the dynamic provider) to select from. However, in Siri, the experience is different. Instead of showing the list of options, Siri asks the user to say the name of the food, and then tries to match it using EntityStringQuery. I originally assumed this might be a design decision to allow hands-free use with voice, but I found that if you use an AppEnum instead, Siri does present a tappable list of options. So now I’m wondering: why the difference? Is there a way to get the @Parameter with AppEntity + optionsProvider to show a tappable list in Siri like it does in Shortcuts or with an AppEnum? Any clarification on how EntityQuery.suggestedEntities() and DynamicOptionsProvider interact with Siri would be appreciated! struct CaloriesShortcuts: AppShortcutsProvider { static var appShortcuts: [AppShortcut] { AppShortcut( intent: AddCaloriesInteractive(), phrases: [ "Add to \(.applicationName)" ], shortTitle: "Calories", systemImageName: "fork" ) } } struct AddCaloriesInteractive: AppIntent { static var title: LocalizedStringResource = "Add to calories log" static var description = IntentDescription("Add Calories using Shortcuts.") static var openAppWhenRun: Bool = false static var parameterSummary: some ParameterSummary { Summary("Calorie Entry SUMMARY") } var displayRepresentation: DisplayRepresentation { DisplayRepresentation(stringLiteral:"Add to calorie log") } @Dependency private var persistenceManager: PersistenceManager @Parameter(title: LocalizedStringResource("Food"), optionsProvider: FoodEntityOptions()) var foodEntity: FoodEntity @MainActor func perform() async throws -> some IntentResult & ProvidesDialog { return .result(dialog: .init("Added \(foodEntity.name) to calorie log")) } } struct FoodEntity: AppEntity { static var defaultQuery = FoodEntityQuery() @Property var name: String @Property var calories: Int init(name: String, calories: Int) { self.name = name self.calories = calories } static var typeDisplayRepresentation: TypeDisplayRepresentation { TypeDisplayRepresentation(name: "Calorie Entry") } static var typeDisplayName: LocalizedStringResource = "Calorie Entry" var displayRepresentation: AppIntents.DisplayRepresentation { DisplayRepresentation(title: .init(stringLiteral: name), subtitle: "\(calories)") } var id: String { return name } } struct FoodEntityQuery: EntityQuery { func entities(for identifiers: [FoodEntity.ID]) async throws -> [FoodEntity] { var result = [FoodEntity]() for identifier in identifiers { if let entity = FoodDatabase.allEntities().first(where: { $0.id == identifier }) { result.append(entity) } } return result } func suggestedEntities() async throws -> [FoodEntity] { return FoodDatabase.allEntities() } } extension FoodEntityQuery: EntityStringQuery { func entities(matching string: String) async throws -> [FoodEntity] { return FoodDatabase.allEntities().filter({$0.name.localizedCaseInsensitiveCompare(string) == .orderedSame}) } } struct FoodEntityOptions: DynamicOptionsProvider { func results() async throws -> ItemCollection<FoodEntity> { ItemCollection { ItemSection("Section 1") { for entry in FoodDatabase.allEntities() { entry } } } } } struct FoodDatabase { // Fake data static func allEntities() -> [FoodEntity] { [ FoodEntity(name: "Orange", calories: 2), FoodEntity(name: "Banana", calories: 2) ] } }
0
1
101
May ’25
Ignore Home Screen Tint/Accents in Colored Components
I'm having some trouble getting my widget to display how I want when the user has a tint applied to their home screen. The issue I'm having is with a Text() element, as well as a LinearGradient I am displaying on top of my image. The text should always be white, and the gradient is always black with varying levels of opacity. I've managed to fix this issue with images displayed in my widget by leveraging widgetAccentedRenderingMode(.fullColor) however, there does not seem to be an equivalent of this for non-Image components. I'm aware of .widgetAccentable(false) but as I understand it, elements are already considered not accentable by default and you need to explicitly declare widgetAccentable(true) to add them to the accent group. I've tried specifying this to be false up and down my view hierarchy just to see if something will stick but no luck. Are there any other levers I can pull to preserve the declared colors for my text and gradient components? The images I am displaying is album artwork where preserving the original image is integral, but the tinted text color and overlaid gradient often clash or just looks bad in general. Is there a solution for colored primitive elements?
0
0
143
Aug ’25
iOS 26 Beta 3 ScrollPosition object not executing scroll commands while scrollPosition(id:) binding works
I'm implementing a horizontal carousel in iOS 26 Beta 3 using SwiftUI ScrollView with LazyHStack. The goal is to programmatically scroll to a specific card on view load. What I'm trying to do: Display a horizontal carousel of cards using ScrollView + LazyHStack Automatically scroll to the "current" card when the view appears Use iOS 26's new ScrollPosition object for programmatic scrolling Current behavior: The ScrollPosition object receives scroll commands (confirmed via console logs) The scrollTo(id:anchor:) method executes without errors However, the ScrollView does not actually scroll - it remains at position 0 Manual scrolling and scrollTargetBehavior(.viewAligned) work perfectly Code snippet: @State private var scrollPositionObject = ScrollPosition() ScrollView(.horizontal) { LazyHStack(spacing: 16) { ForEach(cards, id: .id) { card in CardView(card: card) .id(card.id) } } .scrollTargetLayout() } .scrollPosition($scrollPositionObject) .scrollTargetBehavior(.viewAligned) .onAppear { let targetId = cards[currentIndex].id DispatchQueue.main.asyncAfter(deadline: .now() + 0.3) { scrollPositionObject.scrollTo(id: targetId, anchor: .center) } } Workaround that works: Using the iOS 17 scrollPosition(id:) binding instead of the ScrollPosition object: @State private var scrollPosition: UUID? .scrollPosition(id: $scrollPosition) .onAppear { scrollPosition = cards[currentIndex].id } Environment: iOS 26 Beta 3 Xcode 26 Beta 3 Physical device (iPhone 16 Pro Max) Is this a known issue with ScrollPosition in Beta 3, or am I missing something in the implementation? The older binding approach works fine, but I'd prefer to use the new ScrollPosition API if possible.
Topic: UI Frameworks SubTopic: SwiftUI
0
1
153
Jul ’25
Unable to Drag 3D Model(Entity) in visionOS when UITextView Is in the Background
I'm running into an issue in Xcode when working on a visionOS app. Whenever I try to drag a 3D model entity in my scene, the drag gesture doesn't work if there's a UITextView (or SwiftUI TextEditor) in background of the 3D entity. It seems like the UITextView is intercepting the gesture or preventing the drag interaction from reaching the 3D content. Interestingly, when the 3D entity is placed infront of the ScrollView, the drag works as expected. Has anyone else experienced this behavior? Is this a known limitation or a bug in the current tooling? Any workarounds or fixes would be appreciated. Thanks!
0
0
219
Jul ’25
How to customize item transitions inside a Picker View?
I have a simple Picker where the options available change by the view state. I would like to have the transition animated but the default animation is not good so I tried setting a .transition() and or an .animation() inside an item on the picker but it is ignored. The same happens if the transition is set on the picker itself since it's always present. Am I doing it right and is just not posible or is there something else to do? Code to reproduce the issue: struct ContentView: View { @State var list: [String] = [ "Item 4", "Item 5", "Item 6", "Item 7", "Item 8", ] @State var selected: String? @State var toggle: Bool = false var body: some View { VStack { Picker("List", selection: $selected) { ForEach(list, id: \.self) { Text($0).tag($0) // .transition(.opacity) } } .pickerStyle(.segmented) // .transition(.opacity) HStack { Button(action: swapOptions) { Text("Swap") } } } .padding() } } extension ContentView { func swapOptions() { withAnimation { toggle.toggle() switch toggle { case true: list = [ "Item 1", "Item 2", "Item 3", "Item 4", "Item 5", ] case false: list = [ "Item 4", "Item 5", "Item 6", "Item 7", "Item 8", ] } } } } ``
Topic: UI Frameworks SubTopic: SwiftUI
0
0
99
May ’25
Using NSHostingSceneRepresentation to open arbitrary window in AppKit app
I’m trying to open a window from a SwiftUI Scene inside an AppKit app using NSHostingSceneRepresentation (macOS 26). The idea is that I want to call openWindow(id: "some-id") to show the new window. However, nothing happens when I try this — no window appears, and there’s nothing in the logs. Interestingly, if I use the openSettings() route instead, it does open a window. Does anyone know the correct way to open an arbitrary SwiftUI window scene from an AppKit app? import Cocoa import SwiftUI @main class AppDelegate: NSObject, NSApplicationDelegate { let settingsScene = NSHostingSceneRepresentation { #if true MyWindowScene() #else Settings { Text("My Settings") } #endif } func applicationWillFinishLaunching(_ notification: Notification) { NSApplication.shared.addSceneRepresentation(settingsScene) } @IBAction func showAppSettings(_ sender: NSMenuItem) { #if true settingsScene.environment.openWindow(id: MyWindowScene.windowID) #else settingsScene.environment.openSettings() #endif } } struct MyWindowScene: Scene { static let windowID = "com.company.MySampleApp.myWindow" var body: some Scene { Window("Sample Window", id: MyWindowScene.windowID) { Text("Sample Content") .scenePadding() } } }
Topic: UI Frameworks SubTopic: SwiftUI
0
0
120
Jul ’25
Buttons in the bottom bar of an inspector appear disabled
Buttons placed in the bottomBar and keyboard toolbar item positions in an inspector appear disabled/grayed out when at the large presentation detent. The same is not true for sheets. Is this intentional or a bug? If intentional, is there any backing design theory in the Human Interface Guidelines for it? Xcode 16.4 / 18.5 simulator // Inspector @ large detent struct ContentView: View { var body: some View { Color.clear .inspector(isPresented: .constant(true)) { Color.clear .presentationDetents([.large]) .toolbar { ToolbarItem(placement: .bottomBar) { Button("Save") {} .border(.red) } } } } } // Sheet struct ContentView: View { var body: some View { Color.clear .sheet(isPresented: .constant(true)) { Color.clear .presentationDetents([.medium]) .toolbar { ToolbarItem(placement: .bottomBar) { Button("Save") {} .border(.red) } } } } }
0
0
153
Jul ’25
Pushing a UIHostingController has delayed toolbar items and title transitions
For over five years, this persistent issue has affected all platforms, and despite submitting numerous feedback reports, my concerns have remained unaddressed. When utilizing a UIHostingController within a UINavigationController, the toolbar items and title defined in the SwiftUI view manifest with a substantial delay. This delay is particularly noticeable with the introduction of Liquid Glass, resulting in a jarring transition. Although I had nearly lost hope, the issue was resolved in iOS 26 beta 3 when the push occurs from within a UISplitViewController. However, the problem persists outside of this context. Ultimately, this issue hinders my ability to develop high-quality applications and restricts my use of SwiftUI within my UIKit project for similar purposes. I sincerely hope that this issue can be resolved, enabling me to fully rely on SwiftUI in my project. Please prioritize this matter and make the necessary changes that were already made in UISplitViewController. This feedback has all the details and a sample project. FB14000542 Before the push: During the push: A second after the push finishes:
0
1
165
Jul ’25
FileExporter's action label always says "Move"
I would like to implement an "Export" dialog using the .fileExporter() view modifier. The following code works correctly, but the FileExporter's action label always says "Move", which is inappropriate for the context. I would like to change it to say "Export", "Save", "Save as", or anything semantically correct. Button("Browse") { showingExporter = true } .buttonStyle(.borderedProminent) .fileExporter( isPresented: $showingExporter, document: document, contentType: .data, defaultFilename: suggestedFilename ?? fileUrl.pathComponents.last ?? "Untitled" ) { result in switch result { case .success(let url): print("Saved to \(url)") onSuccess() case .failure(let error): print(error.localizedDescription) onError(error) } } "document" is a custom FileDocument with a fileWrapper() method implemented like this: func fileWrapper(configuration: WriteConfiguration) throws -> FileWrapper { return FileWrapper(regularFileWithContents: data) } This was tested on iOS 26 beta 3.
Topic: UI Frameworks SubTopic: SwiftUI
0
0
124
Jul ’25
Using NavigationSplitView with NavigationStack in it with variable navigation depth (2 and 3 levels) — unexpected back navigation on iPhone
I’m building a cross-platform app targeting macOS, iPad, and iPhone. My app currently uses both 2-level and 3-level navigation workflows: 3-level navigation: First level: Categories Second level: List of items in the selected category Third level: Detail view for a specific item 2-level navigation: First level: Category Second level: A singleton detail view (for example, StatusView). It does not have concept of List. After watching a couple of WWDC videos about multi-platform navigation, I decided to go with NavigationSplitView. However, on macOS, a 3-column NavigationSplitView felt a bit overwhelming to my eyes when the third column was empty—especially for the occasional 2-level navigation case. So I removed the third column and instead embedded a NavigationStack in the second column. According to the official Apple documentation, this is supported: You can also embed a NavigationStack in a column. The code with NavigationStack in NavigationSplitView works fine on macOS. But on iPhone, for the same code I’m seeing unexpected behavior: The first time I tap on the “Actions” category, it briefly shows the “Select an item” view, and then automatically pops back to the all-categories view. If I tap the same "Actions" category again, it shows the list of actions correctly, and everything works fine until I terminate and relaunch the app. Here is a minimal reproducible example: import SwiftUI struct StatusView: View { var body: some View { NavigationStack { List { Text("Heartbeat: OK") Text("Connected to backend: OK") } } } } struct ActionListView: View { var body: some View { NavigationStack { List { NavigationLink(value: "Action 1 value") { Text("Action 1 label") } NavigationLink(value: "Action 2 value") { Text("Action 2 label") } } } .navigationDestination(for: String.self) { action in Text(action) } } } struct ContentView: View { var body: some View { NavigationSplitView { List { NavigationLink(value: "Actions") { Text("Actions (3 level)") } NavigationLink(value: "Modes") { Text("Modes (3 level)") } NavigationLink(value: "State") { Text("Status (2 level)") } } .navigationDestination(for: String.self) { category in switch category { case "Actions": ActionListView() case "Modes": Text("Modes View") case "State": StatusView() default: Text("Unknown Category") } } } detail: { Text("Select an item") } } } Questions and considerations: How can I prevent this unexpected automatic pop back to the root view on iPhone the first time I select a category? Future-proofing for more than 3 level navigation: In the future, I may allow users to navigate beyond three levels (e.g., an item in one category can reference another item in a different category). Is it correct to assume that to support this with back navigation, I’d need to keep using NavigationStack inside NavigationSplitView? Is embedding NavigationStack in a 2 column NavigationSplitView the only practical approach to handle mixed 2 and 3 navigation depth if I don't want the third column to be ever empty? On macOS, NavigationStack alone doesn’t feel appropriate for sidebar-based navigation. Does it mean everyone on macOS pretty much always use NavigationSplitView? Any advice or examples would be appreciated. Thanks!
Topic: UI Frameworks SubTopic: SwiftUI
0
0
135
Jul ’25
[SwiftUI] SecureEntry Autofill in Dark Mode
When using New Password Autofill in Dark Mode, it appears that SecureEntry sets the background color to white and applies a yellow-ish overlay, but doesn't adapt the foreground text color accordingly. This gives the illusion that the SecureEntry field is empty, as we have white text on a white background. Is there a holistic and SwiftUI-native way of fixing this?
0
0
60
Apr ’25
CanvasView overlay on PDFKit loses quality when zoomed – how to preserve drawing resolution?
Hi all, I’m currently building a SwiftUI app that overlays a PKCanvasView onto each page of a PDFView using PDFPageOverlayViewProvider. It works well at the initial scale, but once I zoom into the PDF, the drawings on the PKCanvasView appear blurry or pixelated, even though the PDF itself remains crisp. I’m trying to adjust canvasView.contentScaleFactor relative to pdfView.scaleFactor to preserve the drawing quality. Here’s a simplified version of the relevant code: import SwiftUI import PDFKit import PencilKit struct ContentView: View { var body: some View { if let url = Bundle.main.url(forResource: "sample", withExtension: "pdf"), let data = try? Data(contentsOf: url), let document = PDFDocument(data: data) { PDFRepresentableView(document: document) } else { Text("") } } } #Preview { ContentView() } struct PDFRepresentableView: UIViewRepresentable { let document: PDFDocument let pdfView = PDFView() func makeUIView(context: Context) -> PDFView { pdfView.displayMode = .singlePageContinuous pdfView.usePageViewController(false) pdfView.displayDirection = .vertical pdfView.pageOverlayViewProvider = context.coordinator pdfView.document = document pdfView.autoScales = false pdfView.minScaleFactor = 0.7 pdfView.maxScaleFactor = 4 NotificationCenter.default.addObserver( context.coordinator, selector: #selector(context.coordinator.onPageZoomAndPan), name: .PDFViewScaleChanged, object: pdfView ) return pdfView } func updateUIView(_ uiView: PDFView, context: Context) { // Optional: update logic if needed } func makeCoordinator() -> CustomCoordinator { return CustomCoordinator(parent: self) } } class CustomCoordinator: NSObject, PDFPageOverlayViewProvider, PKCanvasViewDelegate { let parent: PDFRepresentableView init(parent: PDFRepresentableView) { self.parent = parent } func pdfView(_ view: PDFView, overlayViewFor page: PDFPage) -> UIView? { let canvasView = PKCanvasView() let rect = page.bounds(for: .mediaBox) canvasView.drawingPolicy = .anyInput canvasView.tool = PKInkingTool(.pen, color: .black, width: 10) canvasView.translatesAutoresizingMaskIntoConstraints = true canvasView.backgroundColor = .red.withAlphaComponent(0.1) canvasView.frame = rect canvasView.isScrollEnabled = false for subView in view.documentView?.subviews ?? [] { subView.isUserInteractionEnabled = true } return canvasView } @objc func onPageZoomAndPan() { parent.pdfView.documentView?.subviews.forEach { subview in if subview.theClassName == "PDFPageView", let pageViewPrivate = subview.value(forKey: "_private") as? NSObject, let page = pageViewPrivate.value(forKey: "page") as? PDFPage { subview.subviews.forEach { subview in if let canvasView = subview as? PKCanvasView { let zoomScale = parent.pdfView.scaleFactor canvasView.contentScaleFactor = UIScreen.main.scale * zoomScale canvasView.drawing = canvasView.drawing canvasView.setNeedsDisplay() canvasView.layoutIfNeeded() } } } } print("Zoom changed. Current scale: \(parent.pdfView.scaleFactor)") } } extension NSObject { var theClassName: String { return NSStringFromClass(type(of: self)) } } But this doesn’t seem to improve the rendered quality. The lines still appear blurry when zoomed in. What I’ve tried: • Adjusting contentScaleFactor and forcing redraw • Reassigning canvasView.drawing • Calling setNeedsDisplay() and layoutIfNeeded() None of these approaches seem to re-render the canvas at a higher resolution or match the zoomed scale of the PDF. My questions: 1. Is there a correct way to scale PKCanvasView content to match PDF zoom levels? 2. Should I recreate the canvas or drawing when zoom changes? 3. Is PKCanvasView just not intended to handle high zoom fidelity? If anyone has successfully overlaid high-resolution canvas drawing on a zoomable PDFView, I’d love to hear how you managed it. Thanks in advance!
0
0
244
Jul ’25
How do I maintain different navigation selections on a per-scene basis in SwiftUI?
I’ll preface this by saying I’ve submitted a DTS ticket with essentially this exact text, but I thought I’d also post about it here to get some additional input. Apple engineers: the case ID is 14698374, for your reference. I have an observable class, called NavigationModel, that powers navigation in my SwiftUI app. It has one important property, navigationSelection, that stores the currently selected view. This property is passed to a List in the sidebar column of a NavigationSplitView with two columns. The list has NavigationLinks that accept that selection as a value parameter. When a NavigationLink is tapped, the detail column shows the appropriate detail view per the navigationSelection property’s current value via a switch statement. (This navigationSelection stores an enum value.) This setup allows for complete programmatic navigation as that selection is effectively global. From anywhere in the app — any button, command, or app intent — the selection can be modified since the NavigationModel class uses the @Observable Swift macro. In the app’s root file, an instance of the NavigationModel is created, added as an app intent dependency, and assigned (might be the wrong verb here, but you get it) to ContentView, which houses the NavigationSplitView code. The problem lies when more than one window is opened. Because this is all just one instance of NavigationModel — initialized in the app’s root file — the navigation selection is shared across windows. That is, there is no way for one window to show a view and another to show another view — they’re bound to the same instance of NavigationModel. Again, this was done so that app intents and menu bar commands can modify the navigation selection, but this causes unintended behavior. I checked Apple’s sample projects, namely the “Accelerating app interactions with App Intents” (https://aninterestingwebsite.com/documentation/appintents/acceleratingappinteractionswithappintents) and “Adopting App Intents to support system experiences” (https://aninterestingwebsite.com/documentation/appintents/adopting-app-intents-to-support-system-experiences) projects, to see how Apple recommends handling this case. Both of these projects have intents to display a view by modifying the navigation selection. They also have the same unintended behavior I’m experiencing in my app. If two windows are open, they share the navigation selection. I feel pretty stupid asking for help with this, but I’ve tried a lot to get it to work the way I want it to. My first instinct was to create a new instance of NavigationModel for each window, and that’s about 90% of the way there, but app intents fail when there are no open windows because there are no instances of NavigationModel to modify. I also tried playing with FocusedValue and SceneStorage, but those solutions also didn’t play well with app intents and added too much convoluted code for what should be a simple issue. In total, what I want is: A window/scene-specific navigation selection property that works across TabViews and NavigationSplitViews A way to reliably modify that property’s value across the app for the currently focused window A way to set a value as a default, so when the app launches with a window, it automatically selects a value in the detail column The navigation selection to reset across app and window launches, restoring the default selection Does anyone know how to do this? I’ve scoured the internet, but again, no dice. Usually Apple’s sample projects are great with this sort of thing, but all of their projects that have scene-specific navigation selection with NavigationSplitView don’t have app intents. 🤷‍♂️ If anyone needs additional code samples, I’d be happy to provide them, but it’s basically a close copy of Apple’s own sample code found in those two links.
0
0
145
Jul ’25
How to scale a SwiftUI view to fit its parent
Code that reproduces the issue import SwiftUI @main struct KeyboardLayoutProblemApp: App { var body: some Scene { WindowGroup { iOSTabView() } } } struct iOSTabView: View { var body: some View { TabView { GameView() .frame(maxWidth: UIScreen.main.bounds.width, maxHeight: UIScreen.main.bounds.height) .tabItem { Label("Play", systemImage: "gamecontroller.fill") } } } } struct GameView: View { var body: some View { VStack { Text("Play") Spacer() KeyboardView() } .padding() } } struct KeyboardView: View { let firstRowLetters = "qwertyuiop".map { $0 } let secondRowLetters = "asdfghjkl".map { $0 } let thirdRowLetters = "zxcvbnm".map { $0 } var body: some View { VStack { HStack { ForEach(firstRowLetters, id: \.self) { LetterKeyView(character: $0) } } HStack { ForEach(secondRowLetters, id: \.self) { LetterKeyView(character: $0) } } HStack { ForEach(thirdRowLetters, id: \.self) { LetterKeyView(character: $0) } } } .padding() } } struct LetterKeyView: View { let character: Character var width: CGFloat { height*0.8 } @ScaledMetric(relativeTo: .title3) private var height = 35 var body: some View { Button { print("\(character) pressed") } label: { Text(String(character).capitalized) .font(.title3) .frame(width: self.width, height: self.height) .background { RoundedRectangle(cornerRadius: min(width, height)/4, style: .continuous) .stroke(.gray) } } .buttonStyle(PlainButtonStyle()) } } Problem GameView doesn't fit its parent view: Question How do I make GameView be at most as big as its parent view? What I've tried and didn't work GameView() .frame(maxWidth: .infinity, maxHeight: .infinity) GeometryReader { geometry in GameView() .frame(maxWidth: geometry.size.width, maxHeight: geometry.size.height) } GameView() .clipped() GameView() .layoutPriority(1) GameView() .scaledToFit() GameView() .minimumScaleFactor(0.01) GameView() .scaledToFill() .minimumScaleFactor(0.5) I'm not using UIScreen.main.bounds.width because I'm trying to build a multi-platform app.
Topic: UI Frameworks SubTopic: SwiftUI
0
0
96
Jul ’25
MFMessageComposeViewController: Close button disappears after sending message on iOS 26
Description When presenting MFMessageComposeViewController from SwiftUI using UIViewControllerRepresentable, the close button disappears after sending a message on iOS 26. As a result, the message compose screen cannot be dismissed, leaving the user stuck on the Messages UI. struct MessageComposeView: UIViewControllerRepresentable { typealias Completion = (_ messageSent: Bool) -> Void static var canSendText: Bool { MFMessageComposeViewController.canSendText() } let recipients: [String]? let body: String? let completion: Completion? func makeUIViewController(context: Context) -> UIViewController { guard Self.canSendText else { let errorView = MessagesUnavailableView() return UIHostingController(rootView: errorView) } let controller = MFMessageComposeViewController() controller.messageComposeDelegate = context.coordinator controller.recipients = recipients controller.body = body return controller } func updateUIViewController(_ uiViewController: UIViewController, context: Context) {} func makeCoordinator() -> Coordinator { Coordinator(completion: self.completion) } class Coordinator: NSObject, MFMessageComposeViewControllerDelegate { private let completion: Completion? public init(completion: Completion?) { self.completion = completion } public func messageComposeViewController(_ controller: MFMessageComposeViewController, didFinishWith result: MessageComposeResult) { if result == .cancelled { controller.dismiss(animated: true, completion: nil) } completion?(result == .sent) } } } Before sending message: After sending message:
Topic: UI Frameworks SubTopic: SwiftUI
0
1
114
Nov ’25
iOS26 - search
I have several locations in my app where the user can search. He can search within the apps content or search for content from the web to add to the app. i would like to use the tab view search box for both, but I don’t know how to do that. I currently have a tab with value search for the „web search“ and a list with .searchable for the in app content. The later one adds the search bar on top of the list. W hat’s the best way to modify this behavior?
Topic: UI Frameworks SubTopic: SwiftUI
Replies
0
Boosts
0
Views
188
Activity
Jul ’25
Live activity widget not updated locally after server update
I am using live activity in my app. Functionality is start, update & end events are started from the server. There is one interaction button added using app intent in live activity widget. That button needs to update widget ui locally using activity kit. Issue is when os receives first start event push then update ui works fine and reflecting on live activity widget but when update notification receives by os after 1 mins then action button stops updating the ui locally. Can anyone please add some suggestions to fix this.
Replies
0
Boosts
0
Views
139
Activity
May ’25
iPadOS textFormatting menu does not appeared
I have this in my swift file: CommandGroup(replacing: .textFormatting) { Toggle("Bold Text", systemImage: "bold", isOn: boldBinding) .keyboardShortcut("B") Button("Align Left", systemImage: "text.alignleft") { alignmentBinding.wrappedValue = 1 } .keyboardShortcut("[") Button("Align Center", systemImage: "text.aligncenter") { alignmentBinding.wrappedValue = 0 } .keyboardShortcut("\\") Button("Align Right", systemImage: "text.alignright") { alignmentBinding.wrappedValue = 2 } .keyboardShortcut("]") } Nothing appeared in iPadOS menu (but does appeared on Mac). Change textFormatting to textEditing does work, but appeared in a very long menu
Topic: UI Frameworks SubTopic: SwiftUI
Replies
0
Boosts
0
Views
107
Activity
Jul ’25
AppEntity with @Parameter Options Works in Shortcuts App but Not with Siri
I’m working with AppIntents and AppEntity to integrate my app’s data model into Shortcuts and Siri. In the example below, I define a custom FoodEntity and use it as a @Parameter in an AppIntent. I’m providing dynamic options for this parameter via an optionsProvider. In the Shortcuts app, everything works as expected: when the user runs the shortcut, they get a list of food options (from the dynamic provider) to select from. However, in Siri, the experience is different. Instead of showing the list of options, Siri asks the user to say the name of the food, and then tries to match it using EntityStringQuery. I originally assumed this might be a design decision to allow hands-free use with voice, but I found that if you use an AppEnum instead, Siri does present a tappable list of options. So now I’m wondering: why the difference? Is there a way to get the @Parameter with AppEntity + optionsProvider to show a tappable list in Siri like it does in Shortcuts or with an AppEnum? Any clarification on how EntityQuery.suggestedEntities() and DynamicOptionsProvider interact with Siri would be appreciated! struct CaloriesShortcuts: AppShortcutsProvider { static var appShortcuts: [AppShortcut] { AppShortcut( intent: AddCaloriesInteractive(), phrases: [ "Add to \(.applicationName)" ], shortTitle: "Calories", systemImageName: "fork" ) } } struct AddCaloriesInteractive: AppIntent { static var title: LocalizedStringResource = "Add to calories log" static var description = IntentDescription("Add Calories using Shortcuts.") static var openAppWhenRun: Bool = false static var parameterSummary: some ParameterSummary { Summary("Calorie Entry SUMMARY") } var displayRepresentation: DisplayRepresentation { DisplayRepresentation(stringLiteral:"Add to calorie log") } @Dependency private var persistenceManager: PersistenceManager @Parameter(title: LocalizedStringResource("Food"), optionsProvider: FoodEntityOptions()) var foodEntity: FoodEntity @MainActor func perform() async throws -> some IntentResult & ProvidesDialog { return .result(dialog: .init("Added \(foodEntity.name) to calorie log")) } } struct FoodEntity: AppEntity { static var defaultQuery = FoodEntityQuery() @Property var name: String @Property var calories: Int init(name: String, calories: Int) { self.name = name self.calories = calories } static var typeDisplayRepresentation: TypeDisplayRepresentation { TypeDisplayRepresentation(name: "Calorie Entry") } static var typeDisplayName: LocalizedStringResource = "Calorie Entry" var displayRepresentation: AppIntents.DisplayRepresentation { DisplayRepresentation(title: .init(stringLiteral: name), subtitle: "\(calories)") } var id: String { return name } } struct FoodEntityQuery: EntityQuery { func entities(for identifiers: [FoodEntity.ID]) async throws -> [FoodEntity] { var result = [FoodEntity]() for identifier in identifiers { if let entity = FoodDatabase.allEntities().first(where: { $0.id == identifier }) { result.append(entity) } } return result } func suggestedEntities() async throws -> [FoodEntity] { return FoodDatabase.allEntities() } } extension FoodEntityQuery: EntityStringQuery { func entities(matching string: String) async throws -> [FoodEntity] { return FoodDatabase.allEntities().filter({$0.name.localizedCaseInsensitiveCompare(string) == .orderedSame}) } } struct FoodEntityOptions: DynamicOptionsProvider { func results() async throws -> ItemCollection<FoodEntity> { ItemCollection { ItemSection("Section 1") { for entry in FoodDatabase.allEntities() { entry } } } } } struct FoodDatabase { // Fake data static func allEntities() -> [FoodEntity] { [ FoodEntity(name: "Orange", calories: 2), FoodEntity(name: "Banana", calories: 2) ] } }
Replies
0
Boosts
1
Views
101
Activity
May ’25
Ignore Home Screen Tint/Accents in Colored Components
I'm having some trouble getting my widget to display how I want when the user has a tint applied to their home screen. The issue I'm having is with a Text() element, as well as a LinearGradient I am displaying on top of my image. The text should always be white, and the gradient is always black with varying levels of opacity. I've managed to fix this issue with images displayed in my widget by leveraging widgetAccentedRenderingMode(.fullColor) however, there does not seem to be an equivalent of this for non-Image components. I'm aware of .widgetAccentable(false) but as I understand it, elements are already considered not accentable by default and you need to explicitly declare widgetAccentable(true) to add them to the accent group. I've tried specifying this to be false up and down my view hierarchy just to see if something will stick but no luck. Are there any other levers I can pull to preserve the declared colors for my text and gradient components? The images I am displaying is album artwork where preserving the original image is integral, but the tinted text color and overlaid gradient often clash or just looks bad in general. Is there a solution for colored primitive elements?
Replies
0
Boosts
0
Views
143
Activity
Aug ’25
ShareLink in iPad menu bar does not show up
This is my code: CommandGroup(before: .printItem) { ShareLink(item: answer) .disabled(answer.isEmpty) } It works fine on Mac, when selecting the share menu from Mac, it works. But when select from iPad menu bar, nothing shows up.
Topic: UI Frameworks SubTopic: SwiftUI
Replies
0
Boosts
0
Views
85
Activity
Jul ’25
iOS 26 Beta 3 ScrollPosition object not executing scroll commands while scrollPosition(id:) binding works
I'm implementing a horizontal carousel in iOS 26 Beta 3 using SwiftUI ScrollView with LazyHStack. The goal is to programmatically scroll to a specific card on view load. What I'm trying to do: Display a horizontal carousel of cards using ScrollView + LazyHStack Automatically scroll to the "current" card when the view appears Use iOS 26's new ScrollPosition object for programmatic scrolling Current behavior: The ScrollPosition object receives scroll commands (confirmed via console logs) The scrollTo(id:anchor:) method executes without errors However, the ScrollView does not actually scroll - it remains at position 0 Manual scrolling and scrollTargetBehavior(.viewAligned) work perfectly Code snippet: @State private var scrollPositionObject = ScrollPosition() ScrollView(.horizontal) { LazyHStack(spacing: 16) { ForEach(cards, id: .id) { card in CardView(card: card) .id(card.id) } } .scrollTargetLayout() } .scrollPosition($scrollPositionObject) .scrollTargetBehavior(.viewAligned) .onAppear { let targetId = cards[currentIndex].id DispatchQueue.main.asyncAfter(deadline: .now() + 0.3) { scrollPositionObject.scrollTo(id: targetId, anchor: .center) } } Workaround that works: Using the iOS 17 scrollPosition(id:) binding instead of the ScrollPosition object: @State private var scrollPosition: UUID? .scrollPosition(id: $scrollPosition) .onAppear { scrollPosition = cards[currentIndex].id } Environment: iOS 26 Beta 3 Xcode 26 Beta 3 Physical device (iPhone 16 Pro Max) Is this a known issue with ScrollPosition in Beta 3, or am I missing something in the implementation? The older binding approach works fine, but I'd prefer to use the new ScrollPosition API if possible.
Topic: UI Frameworks SubTopic: SwiftUI
Replies
0
Boosts
1
Views
153
Activity
Jul ’25
iOS 26 List selection radius
Is there any way to influence the corner radius of a selection in the list? Looking at the native Apple Mail app in the iOS 26, it should be.
Topic: UI Frameworks SubTopic: SwiftUI
Replies
0
Boosts
1
Views
167
Activity
Jun ’25
Unable to Drag 3D Model(Entity) in visionOS when UITextView Is in the Background
I'm running into an issue in Xcode when working on a visionOS app. Whenever I try to drag a 3D model entity in my scene, the drag gesture doesn't work if there's a UITextView (or SwiftUI TextEditor) in background of the 3D entity. It seems like the UITextView is intercepting the gesture or preventing the drag interaction from reaching the 3D content. Interestingly, when the 3D entity is placed infront of the ScrollView, the drag works as expected. Has anyone else experienced this behavior? Is this a known limitation or a bug in the current tooling? Any workarounds or fixes would be appreciated. Thanks!
Replies
0
Boosts
0
Views
219
Activity
Jul ’25
How to customize item transitions inside a Picker View?
I have a simple Picker where the options available change by the view state. I would like to have the transition animated but the default animation is not good so I tried setting a .transition() and or an .animation() inside an item on the picker but it is ignored. The same happens if the transition is set on the picker itself since it's always present. Am I doing it right and is just not posible or is there something else to do? Code to reproduce the issue: struct ContentView: View { @State var list: [String] = [ "Item 4", "Item 5", "Item 6", "Item 7", "Item 8", ] @State var selected: String? @State var toggle: Bool = false var body: some View { VStack { Picker("List", selection: $selected) { ForEach(list, id: \.self) { Text($0).tag($0) // .transition(.opacity) } } .pickerStyle(.segmented) // .transition(.opacity) HStack { Button(action: swapOptions) { Text("Swap") } } } .padding() } } extension ContentView { func swapOptions() { withAnimation { toggle.toggle() switch toggle { case true: list = [ "Item 1", "Item 2", "Item 3", "Item 4", "Item 5", ] case false: list = [ "Item 4", "Item 5", "Item 6", "Item 7", "Item 8", ] } } } } ``
Topic: UI Frameworks SubTopic: SwiftUI
Replies
0
Boosts
0
Views
99
Activity
May ’25
Using NSHostingSceneRepresentation to open arbitrary window in AppKit app
I’m trying to open a window from a SwiftUI Scene inside an AppKit app using NSHostingSceneRepresentation (macOS 26). The idea is that I want to call openWindow(id: "some-id") to show the new window. However, nothing happens when I try this — no window appears, and there’s nothing in the logs. Interestingly, if I use the openSettings() route instead, it does open a window. Does anyone know the correct way to open an arbitrary SwiftUI window scene from an AppKit app? import Cocoa import SwiftUI @main class AppDelegate: NSObject, NSApplicationDelegate { let settingsScene = NSHostingSceneRepresentation { #if true MyWindowScene() #else Settings { Text("My Settings") } #endif } func applicationWillFinishLaunching(_ notification: Notification) { NSApplication.shared.addSceneRepresentation(settingsScene) } @IBAction func showAppSettings(_ sender: NSMenuItem) { #if true settingsScene.environment.openWindow(id: MyWindowScene.windowID) #else settingsScene.environment.openSettings() #endif } } struct MyWindowScene: Scene { static let windowID = "com.company.MySampleApp.myWindow" var body: some Scene { Window("Sample Window", id: MyWindowScene.windowID) { Text("Sample Content") .scenePadding() } } }
Topic: UI Frameworks SubTopic: SwiftUI
Replies
0
Boosts
0
Views
120
Activity
Jul ’25
Buttons in the bottom bar of an inspector appear disabled
Buttons placed in the bottomBar and keyboard toolbar item positions in an inspector appear disabled/grayed out when at the large presentation detent. The same is not true for sheets. Is this intentional or a bug? If intentional, is there any backing design theory in the Human Interface Guidelines for it? Xcode 16.4 / 18.5 simulator // Inspector @ large detent struct ContentView: View { var body: some View { Color.clear .inspector(isPresented: .constant(true)) { Color.clear .presentationDetents([.large]) .toolbar { ToolbarItem(placement: .bottomBar) { Button("Save") {} .border(.red) } } } } } // Sheet struct ContentView: View { var body: some View { Color.clear .sheet(isPresented: .constant(true)) { Color.clear .presentationDetents([.medium]) .toolbar { ToolbarItem(placement: .bottomBar) { Button("Save") {} .border(.red) } } } } }
Replies
0
Boosts
0
Views
153
Activity
Jul ’25
Pushing a UIHostingController has delayed toolbar items and title transitions
For over five years, this persistent issue has affected all platforms, and despite submitting numerous feedback reports, my concerns have remained unaddressed. When utilizing a UIHostingController within a UINavigationController, the toolbar items and title defined in the SwiftUI view manifest with a substantial delay. This delay is particularly noticeable with the introduction of Liquid Glass, resulting in a jarring transition. Although I had nearly lost hope, the issue was resolved in iOS 26 beta 3 when the push occurs from within a UISplitViewController. However, the problem persists outside of this context. Ultimately, this issue hinders my ability to develop high-quality applications and restricts my use of SwiftUI within my UIKit project for similar purposes. I sincerely hope that this issue can be resolved, enabling me to fully rely on SwiftUI in my project. Please prioritize this matter and make the necessary changes that were already made in UISplitViewController. This feedback has all the details and a sample project. FB14000542 Before the push: During the push: A second after the push finishes:
Replies
0
Boosts
1
Views
165
Activity
Jul ’25
FileExporter's action label always says "Move"
I would like to implement an "Export" dialog using the .fileExporter() view modifier. The following code works correctly, but the FileExporter's action label always says "Move", which is inappropriate for the context. I would like to change it to say "Export", "Save", "Save as", or anything semantically correct. Button("Browse") { showingExporter = true } .buttonStyle(.borderedProminent) .fileExporter( isPresented: $showingExporter, document: document, contentType: .data, defaultFilename: suggestedFilename ?? fileUrl.pathComponents.last ?? "Untitled" ) { result in switch result { case .success(let url): print("Saved to \(url)") onSuccess() case .failure(let error): print(error.localizedDescription) onError(error) } } "document" is a custom FileDocument with a fileWrapper() method implemented like this: func fileWrapper(configuration: WriteConfiguration) throws -> FileWrapper { return FileWrapper(regularFileWithContents: data) } This was tested on iOS 26 beta 3.
Topic: UI Frameworks SubTopic: SwiftUI
Replies
0
Boosts
0
Views
124
Activity
Jul ’25
Using NavigationSplitView with NavigationStack in it with variable navigation depth (2 and 3 levels) — unexpected back navigation on iPhone
I’m building a cross-platform app targeting macOS, iPad, and iPhone. My app currently uses both 2-level and 3-level navigation workflows: 3-level navigation: First level: Categories Second level: List of items in the selected category Third level: Detail view for a specific item 2-level navigation: First level: Category Second level: A singleton detail view (for example, StatusView). It does not have concept of List. After watching a couple of WWDC videos about multi-platform navigation, I decided to go with NavigationSplitView. However, on macOS, a 3-column NavigationSplitView felt a bit overwhelming to my eyes when the third column was empty—especially for the occasional 2-level navigation case. So I removed the third column and instead embedded a NavigationStack in the second column. According to the official Apple documentation, this is supported: You can also embed a NavigationStack in a column. The code with NavigationStack in NavigationSplitView works fine on macOS. But on iPhone, for the same code I’m seeing unexpected behavior: The first time I tap on the “Actions” category, it briefly shows the “Select an item” view, and then automatically pops back to the all-categories view. If I tap the same "Actions" category again, it shows the list of actions correctly, and everything works fine until I terminate and relaunch the app. Here is a minimal reproducible example: import SwiftUI struct StatusView: View { var body: some View { NavigationStack { List { Text("Heartbeat: OK") Text("Connected to backend: OK") } } } } struct ActionListView: View { var body: some View { NavigationStack { List { NavigationLink(value: "Action 1 value") { Text("Action 1 label") } NavigationLink(value: "Action 2 value") { Text("Action 2 label") } } } .navigationDestination(for: String.self) { action in Text(action) } } } struct ContentView: View { var body: some View { NavigationSplitView { List { NavigationLink(value: "Actions") { Text("Actions (3 level)") } NavigationLink(value: "Modes") { Text("Modes (3 level)") } NavigationLink(value: "State") { Text("Status (2 level)") } } .navigationDestination(for: String.self) { category in switch category { case "Actions": ActionListView() case "Modes": Text("Modes View") case "State": StatusView() default: Text("Unknown Category") } } } detail: { Text("Select an item") } } } Questions and considerations: How can I prevent this unexpected automatic pop back to the root view on iPhone the first time I select a category? Future-proofing for more than 3 level navigation: In the future, I may allow users to navigate beyond three levels (e.g., an item in one category can reference another item in a different category). Is it correct to assume that to support this with back navigation, I’d need to keep using NavigationStack inside NavigationSplitView? Is embedding NavigationStack in a 2 column NavigationSplitView the only practical approach to handle mixed 2 and 3 navigation depth if I don't want the third column to be ever empty? On macOS, NavigationStack alone doesn’t feel appropriate for sidebar-based navigation. Does it mean everyone on macOS pretty much always use NavigationSplitView? Any advice or examples would be appreciated. Thanks!
Topic: UI Frameworks SubTopic: SwiftUI
Replies
0
Boosts
0
Views
135
Activity
Jul ’25
[SwiftUI] SecureEntry Autofill in Dark Mode
When using New Password Autofill in Dark Mode, it appears that SecureEntry sets the background color to white and applies a yellow-ish overlay, but doesn't adapt the foreground text color accordingly. This gives the illusion that the SecureEntry field is empty, as we have white text on a white background. Is there a holistic and SwiftUI-native way of fixing this?
Replies
0
Boosts
0
Views
60
Activity
Apr ’25
CanvasView overlay on PDFKit loses quality when zoomed – how to preserve drawing resolution?
Hi all, I’m currently building a SwiftUI app that overlays a PKCanvasView onto each page of a PDFView using PDFPageOverlayViewProvider. It works well at the initial scale, but once I zoom into the PDF, the drawings on the PKCanvasView appear blurry or pixelated, even though the PDF itself remains crisp. I’m trying to adjust canvasView.contentScaleFactor relative to pdfView.scaleFactor to preserve the drawing quality. Here’s a simplified version of the relevant code: import SwiftUI import PDFKit import PencilKit struct ContentView: View { var body: some View { if let url = Bundle.main.url(forResource: "sample", withExtension: "pdf"), let data = try? Data(contentsOf: url), let document = PDFDocument(data: data) { PDFRepresentableView(document: document) } else { Text("") } } } #Preview { ContentView() } struct PDFRepresentableView: UIViewRepresentable { let document: PDFDocument let pdfView = PDFView() func makeUIView(context: Context) -> PDFView { pdfView.displayMode = .singlePageContinuous pdfView.usePageViewController(false) pdfView.displayDirection = .vertical pdfView.pageOverlayViewProvider = context.coordinator pdfView.document = document pdfView.autoScales = false pdfView.minScaleFactor = 0.7 pdfView.maxScaleFactor = 4 NotificationCenter.default.addObserver( context.coordinator, selector: #selector(context.coordinator.onPageZoomAndPan), name: .PDFViewScaleChanged, object: pdfView ) return pdfView } func updateUIView(_ uiView: PDFView, context: Context) { // Optional: update logic if needed } func makeCoordinator() -> CustomCoordinator { return CustomCoordinator(parent: self) } } class CustomCoordinator: NSObject, PDFPageOverlayViewProvider, PKCanvasViewDelegate { let parent: PDFRepresentableView init(parent: PDFRepresentableView) { self.parent = parent } func pdfView(_ view: PDFView, overlayViewFor page: PDFPage) -> UIView? { let canvasView = PKCanvasView() let rect = page.bounds(for: .mediaBox) canvasView.drawingPolicy = .anyInput canvasView.tool = PKInkingTool(.pen, color: .black, width: 10) canvasView.translatesAutoresizingMaskIntoConstraints = true canvasView.backgroundColor = .red.withAlphaComponent(0.1) canvasView.frame = rect canvasView.isScrollEnabled = false for subView in view.documentView?.subviews ?? [] { subView.isUserInteractionEnabled = true } return canvasView } @objc func onPageZoomAndPan() { parent.pdfView.documentView?.subviews.forEach { subview in if subview.theClassName == "PDFPageView", let pageViewPrivate = subview.value(forKey: "_private") as? NSObject, let page = pageViewPrivate.value(forKey: "page") as? PDFPage { subview.subviews.forEach { subview in if let canvasView = subview as? PKCanvasView { let zoomScale = parent.pdfView.scaleFactor canvasView.contentScaleFactor = UIScreen.main.scale * zoomScale canvasView.drawing = canvasView.drawing canvasView.setNeedsDisplay() canvasView.layoutIfNeeded() } } } } print("Zoom changed. Current scale: \(parent.pdfView.scaleFactor)") } } extension NSObject { var theClassName: String { return NSStringFromClass(type(of: self)) } } But this doesn’t seem to improve the rendered quality. The lines still appear blurry when zoomed in. What I’ve tried: • Adjusting contentScaleFactor and forcing redraw • Reassigning canvasView.drawing • Calling setNeedsDisplay() and layoutIfNeeded() None of these approaches seem to re-render the canvas at a higher resolution or match the zoomed scale of the PDF. My questions: 1. Is there a correct way to scale PKCanvasView content to match PDF zoom levels? 2. Should I recreate the canvas or drawing when zoom changes? 3. Is PKCanvasView just not intended to handle high zoom fidelity? If anyone has successfully overlaid high-resolution canvas drawing on a zoomable PDFView, I’d love to hear how you managed it. Thanks in advance!
Replies
0
Boosts
0
Views
244
Activity
Jul ’25
How do I maintain different navigation selections on a per-scene basis in SwiftUI?
I’ll preface this by saying I’ve submitted a DTS ticket with essentially this exact text, but I thought I’d also post about it here to get some additional input. Apple engineers: the case ID is 14698374, for your reference. I have an observable class, called NavigationModel, that powers navigation in my SwiftUI app. It has one important property, navigationSelection, that stores the currently selected view. This property is passed to a List in the sidebar column of a NavigationSplitView with two columns. The list has NavigationLinks that accept that selection as a value parameter. When a NavigationLink is tapped, the detail column shows the appropriate detail view per the navigationSelection property’s current value via a switch statement. (This navigationSelection stores an enum value.) This setup allows for complete programmatic navigation as that selection is effectively global. From anywhere in the app — any button, command, or app intent — the selection can be modified since the NavigationModel class uses the @Observable Swift macro. In the app’s root file, an instance of the NavigationModel is created, added as an app intent dependency, and assigned (might be the wrong verb here, but you get it) to ContentView, which houses the NavigationSplitView code. The problem lies when more than one window is opened. Because this is all just one instance of NavigationModel — initialized in the app’s root file — the navigation selection is shared across windows. That is, there is no way for one window to show a view and another to show another view — they’re bound to the same instance of NavigationModel. Again, this was done so that app intents and menu bar commands can modify the navigation selection, but this causes unintended behavior. I checked Apple’s sample projects, namely the “Accelerating app interactions with App Intents” (https://aninterestingwebsite.com/documentation/appintents/acceleratingappinteractionswithappintents) and “Adopting App Intents to support system experiences” (https://aninterestingwebsite.com/documentation/appintents/adopting-app-intents-to-support-system-experiences) projects, to see how Apple recommends handling this case. Both of these projects have intents to display a view by modifying the navigation selection. They also have the same unintended behavior I’m experiencing in my app. If two windows are open, they share the navigation selection. I feel pretty stupid asking for help with this, but I’ve tried a lot to get it to work the way I want it to. My first instinct was to create a new instance of NavigationModel for each window, and that’s about 90% of the way there, but app intents fail when there are no open windows because there are no instances of NavigationModel to modify. I also tried playing with FocusedValue and SceneStorage, but those solutions also didn’t play well with app intents and added too much convoluted code for what should be a simple issue. In total, what I want is: A window/scene-specific navigation selection property that works across TabViews and NavigationSplitViews A way to reliably modify that property’s value across the app for the currently focused window A way to set a value as a default, so when the app launches with a window, it automatically selects a value in the detail column The navigation selection to reset across app and window launches, restoring the default selection Does anyone know how to do this? I’ve scoured the internet, but again, no dice. Usually Apple’s sample projects are great with this sort of thing, but all of their projects that have scene-specific navigation selection with NavigationSplitView don’t have app intents. 🤷‍♂️ If anyone needs additional code samples, I’d be happy to provide them, but it’s basically a close copy of Apple’s own sample code found in those two links.
Replies
0
Boosts
0
Views
145
Activity
Jul ’25
How to scale a SwiftUI view to fit its parent
Code that reproduces the issue import SwiftUI @main struct KeyboardLayoutProblemApp: App { var body: some Scene { WindowGroup { iOSTabView() } } } struct iOSTabView: View { var body: some View { TabView { GameView() .frame(maxWidth: UIScreen.main.bounds.width, maxHeight: UIScreen.main.bounds.height) .tabItem { Label("Play", systemImage: "gamecontroller.fill") } } } } struct GameView: View { var body: some View { VStack { Text("Play") Spacer() KeyboardView() } .padding() } } struct KeyboardView: View { let firstRowLetters = "qwertyuiop".map { $0 } let secondRowLetters = "asdfghjkl".map { $0 } let thirdRowLetters = "zxcvbnm".map { $0 } var body: some View { VStack { HStack { ForEach(firstRowLetters, id: \.self) { LetterKeyView(character: $0) } } HStack { ForEach(secondRowLetters, id: \.self) { LetterKeyView(character: $0) } } HStack { ForEach(thirdRowLetters, id: \.self) { LetterKeyView(character: $0) } } } .padding() } } struct LetterKeyView: View { let character: Character var width: CGFloat { height*0.8 } @ScaledMetric(relativeTo: .title3) private var height = 35 var body: some View { Button { print("\(character) pressed") } label: { Text(String(character).capitalized) .font(.title3) .frame(width: self.width, height: self.height) .background { RoundedRectangle(cornerRadius: min(width, height)/4, style: .continuous) .stroke(.gray) } } .buttonStyle(PlainButtonStyle()) } } Problem GameView doesn't fit its parent view: Question How do I make GameView be at most as big as its parent view? What I've tried and didn't work GameView() .frame(maxWidth: .infinity, maxHeight: .infinity) GeometryReader { geometry in GameView() .frame(maxWidth: geometry.size.width, maxHeight: geometry.size.height) } GameView() .clipped() GameView() .layoutPriority(1) GameView() .scaledToFit() GameView() .minimumScaleFactor(0.01) GameView() .scaledToFill() .minimumScaleFactor(0.5) I'm not using UIScreen.main.bounds.width because I'm trying to build a multi-platform app.
Topic: UI Frameworks SubTopic: SwiftUI
Replies
0
Boosts
0
Views
96
Activity
Jul ’25
MFMessageComposeViewController: Close button disappears after sending message on iOS 26
Description When presenting MFMessageComposeViewController from SwiftUI using UIViewControllerRepresentable, the close button disappears after sending a message on iOS 26. As a result, the message compose screen cannot be dismissed, leaving the user stuck on the Messages UI. struct MessageComposeView: UIViewControllerRepresentable { typealias Completion = (_ messageSent: Bool) -> Void static var canSendText: Bool { MFMessageComposeViewController.canSendText() } let recipients: [String]? let body: String? let completion: Completion? func makeUIViewController(context: Context) -> UIViewController { guard Self.canSendText else { let errorView = MessagesUnavailableView() return UIHostingController(rootView: errorView) } let controller = MFMessageComposeViewController() controller.messageComposeDelegate = context.coordinator controller.recipients = recipients controller.body = body return controller } func updateUIViewController(_ uiViewController: UIViewController, context: Context) {} func makeCoordinator() -> Coordinator { Coordinator(completion: self.completion) } class Coordinator: NSObject, MFMessageComposeViewControllerDelegate { private let completion: Completion? public init(completion: Completion?) { self.completion = completion } public func messageComposeViewController(_ controller: MFMessageComposeViewController, didFinishWith result: MessageComposeResult) { if result == .cancelled { controller.dismiss(animated: true, completion: nil) } completion?(result == .sent) } } } Before sending message: After sending message:
Topic: UI Frameworks SubTopic: SwiftUI
Replies
0
Boosts
1
Views
114
Activity
Nov ’25