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)
}
}
}
}
}
SwiftUI
RSS for tagProvide views, controls, and layout structures for declaring your app's user interface using SwiftUI.
Selecting any option will automatically load the page
Post
Replies
Boosts
Views
Activity
In my app, I had an '.commands' region that provided an "Open File" shortcut, bound to Command-o. My app manages multiple files, so this triggers my own file picker and opens the file.
With iOS 2026, the system will not let me use this command, as the system is adding its own handler 'Open...' bound to the same shortcut, and with a target action called open:. My app also relies on LSSupportsOpeningDocumentsInPlace, which I believe is what triggers this behavior.
Attempts to override it produce errors like this:
Replacement elements conflict with existing elements:
Keyboard Shortcut (duplicate modifierFlags: command, input: O):
- Existing keyboard shortcut: <UIKeyCommand: 0x107cf4620> -> Title: Open... Action: open: Input: o + (UIKeyModifierCommand)
- Conflicting keyboard shortcut: <UIKeyCommand: 0x107cf56c0> -> Title: Open Action: _performMainMenuShortcutKeyCommand: Input: o + (UIKeyModifierCommand)
Ensure all keyboard shortcuts are unique to avoid undefined behavior.
Mine is the open without the ellipsis.
I would be happy if I could provide my own implementation of 'Open' and let SwiftUI call it, but I have not found any documentation for how to do this.
I managed to override the buildMenu on the AppDelegate class, and while this removes the system version of 'open' SwiftUI is still going behind my back and disabling the menu entry (I suspect it is looking up the command by shortcut/modifier).
So the closest I could do is to remove the system open menu with the buildMenu override, and then provide my own command with a different keyboard modifier (Control-o, instead of Command-o, which is ugly as hell, as everything else uses Command-Letter).
Any guidance would be appreciated.
Topic:
UI Frameworks
SubTopic:
SwiftUI
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!
To adopt glass effect in custom view, we are using glassEffect modifier. It is working fine iOS26. However in iPadOS 26 beta 3, app is getting crash as soon as app launch. In iPad simulator it's working fine.
Symbol not found: _$s7SwiftUI4ViewPAAE11glassEffect_2inQrAA5GlassV_qd__tAA5ShapeRd__lF
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
I am encounter an issue with the height of a ScrollView not rendering properly during the transition of a sheet from closed to open. This results in a gap between the bottom edge of the ScrollView and the bottom edge of the sheet during the animation. I am getting this issue when trying to use the ScrollView inside a NavigationStack and when using a PresentationDetent other than .large.
The code snippet below, for example, suffers from the issue.
ScrollView {
Button("Reveal sheet") {
isPresented = true
}
}
.frame(maxWidth: .infinity)
.background(.yellow)
.sheet(isPresented: $isPresented) {
VStack {
NavigationStack {
ScrollView {
ForEach(0..<100, id: \.self) { number in
Text("\(number)")
}
.frame(maxWidth: .infinity)
}
.background(.green)
.presentationDetents([.medium])
}
}
}
Here is what the issue looks like for this example.
The issue occurs in:
Simulator iPhone 16 iOS 18.4
Personal device (iPhone 16 iOS 18.4)
Canvas preview
Is there a way to present a non-anchored confirmation dialogue in iOS26? Maybe some random style modifier I haven't noticed?
Things like menu bars should be able to prompt confirmable actions, but there's not always a convenient place to anchor a popover for those.
Topic:
UI Frameworks
SubTopic:
SwiftUI
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
If you are currently on the beta of iOS 26, open Apple Music and you'll see a tabViewBottomAccessory that is the mini NowPlayingView. When tapped, it opens the NowPlayingView. Is there a similar way to do this in SwiftUI?
Looking through Apple's documentation, they do not specify any way to reproduce the same kind of view transition.
This is the Apple Music app with the tabViewBottomAccessory. When clicked it opens the NowPlayingView
I have a package that I import into my parent project. Everything works fine and compiles in the parent project but when I open the package in Xcode and try to see a view in the simulator, I see this:
What am I doing wrong?
Topic:
UI Frameworks
SubTopic:
SwiftUI
The following code causes an error in Xcode 26.0 beta3 in iOS Simulator with iOS 26.0.
After starting the App, scroll to the end of the grid and the app will break.
Testet with Xcode Playground with platforms: [ .iOS("17.0")],
Simplest possible variant:
import SwiftUI
import MapKit
struct ContentView: View {
var body: some View {
NavigationStack {
ScrollView {
LazyVGrid(columns: [GridItem()]) {
ForEach(1...12, id:\.self) { i in
Text("Hello \(i)")
.frame(height: 150)
}
Map { }
.frame(height: 150)
}
}
}
}
}
Thrown error:
Observation tracking feedback loop detected! Make a symbolic breakpoint at UIObservationTrackingFeedbackLoopDetected to catch this in the debugger. Refer to the console logs for details about recent invalidations; you can also make a symbolic breakpoint at UIObservationTrackingInvalidated to catch invalidations in the debugger. Object receiving repeated [updateProperties] invalidations: <UIKit.NavigationBarContentView: 0x103026000; frame = (0 0; 402 54); gestureRecognizers = <NSArray: 0x600000c26790>; layer = <CALayer: 0x600000c2d4a0>> contentView=0x0000000103026000
These three nested views are necessary to reproduce the error: NavigationStack -> ScrollView -> LazyVGrid
In iOS Simulator with iOS 18.0 there is no error message, the CPU raises to 100%.
With Xcode 16.4 the program runs error-free.
Is there a solution?
I am using AlarmKit to schedule alarms in an app I am working on, however my scheduled alarms only show up on the lock screen. If I am on the home screen or elsewhere I only hear the sound of the alarm, but no UI shows up.
Environment:
iOS 26 beta 3
Xcode 26 beta 3
Topic:
UI Frameworks
SubTopic:
SwiftUI
Code that reproduces the issue
import SwiftUI
@main
struct TextFieldsGridApp: App {
@State private var controller = Controller()
var body: some Scene {
WindowGroup {
GridView()
.environment(controller)
}
}
}
struct GridView: View {
@Environment(Controller.self) private var c
var body: some View {
VStack {
ForEach(0..<c.strings.count, id: \.self) { r in
HStack {
ForEach(0..<4, id: \.self) { c in
TextField(
"",
text: c.strings[r][c]
)
.textFieldStyle(.roundedBorder)
}
}
}
}
.padding()
}
}
#Preview {
GridView()
.environment(Controller())
}
@Observable
class Controller {
private(set) var strings: [[String]] = Array(
repeating: Array(repeating: "A", count: 4),
count: 4,
)
}
Error
Cannot convert value of type 'Range<Int>' to expected argument type 'Binding<C>', caused by ForEach(0..<4, id: \.self) { c in.
Which I do not get if I say, for example:
struct GridView: View {
@State private var text = "H"
// ...
TextField("", text: $text)
Environment
MacBook Air M1 8GB
iOS Sequoia 15.5
Xcode 16.4
Preview: iPhone 16 Pro, iOS 18.5.
Topic:
UI Frameworks
SubTopic:
SwiftUI
The following repro case results in a previews crash on Xcode 26 beta 3 (report attached). FB18762054
import SwiftUI
final class MyItem: Identifiable, Labelled {
var label: String
init(_ label: String) {
self.label = label
}
}
protocol Labelled {
var label: String { get }
}
struct HelloView: View {
let label: String
var body: some View {
Text(label)
}
}
struct ListView<Element: Labelled & Identifiable>: View {
@Binding var elements: [Element]
var body: some View {
List {
ForEach($elements, id: \.id) { $element in
HelloView(label: element.label) // crash
// Replacing the above with a predefined view works correctly
// Text(element.label)
}
}
}
}
struct ForEachBindingRepro: View {
@State var elements: [MyItem] = [
MyItem("hello"),
MyItem("world"),
]
var body: some View {
ListView(elements: $elements)
}
}
#Preview("ForEachBindingRepro") {
ForEachBindingRepro()
}
foreachbindingrepro-2025-07-12-020628.ips
I’m encountering an issue in iOS 18.5 (and most probably across all iOS 18 versions) where the keyboard toolbar defined with .toolbar(.keyboard) does not appear immediately when a TextField becomes first responder inside a fullScreenCover. Here’s a minimal reproducible example:
import SwiftUI
struct ContentView: View {
@State private var text: String = ""
@State private var showSheet: Bool = false
var body: some View {
NavigationStack {
Button("Show Sheet") {
showSheet.toggle()
}
.fullScreenCover(isPresented: $showSheet) {
NavigationStack {
VStack {
Button("Dismiss") {
showSheet.toggle()
}
TextField("Enter text", text: .constant("Hello"))
.autocorrectionDisabled()
.textInputAutocapitalization(.never)
}
.padding()
.toolbar {
ToolbarItemGroup(placement: .keyboard) {
toolBar
}
}
}
}
}
}
private var toolBar: some View {
HStack {
Spacer()
Button("Done") {
UIApplication.shared.sendAction(#selector(UIResponder.resignFirstResponder), to: nil, from: nil, for: nil)
}
}
}
}
✅ Expected Behavior:
When the TextField becomes active and the keyboard appears, the custom keyboard toolbar with a “Done” button should also appear immediately.
❌ Actual Behavior:
On first presentation of the sheet and focusing the TextField, the toolbar is missing.
If I background the app and return, the toolbar appears as expected.
Dismissing and re-opening the sheet leads to the same issue (toolbar missing again).
Topic:
UI Frameworks
SubTopic:
SwiftUI
On iPhone, I would like to have a more button at the top right of the navigation bar, a search field in the bottom toolbar, and a plus button to the right of the search field. I've achieved this via the code below.
But on iPad they should be in the navigation bar at the trailing edge from left to right: plus, more, search field. Just like the Shortcuts app, if there's not enough horizontal space, the search field should collapse into a button, and with even smaller space the search bar should become full-width under the navigation bar.
Right now on iPad the search bar is full width under the navigation bar, more at top right, plus at bottom middle, no matter how big the window is.
How can I achieve that? Any way to specify them for the system to more automatically do the right thing, or would I need to check specifically for iPhone vs iPad UIDevice to change the code?
struct ContentView: View {
@State private var searchText = ""
var body: some View {
NavigationStack {
VStack {
Text("Hello, world!")
}
.navigationTitle("Test App")
.searchable(text: $searchText)
.toolbar {
ToolbarItem {
Menu {
//...
} label: {
Label("More", systemImage: "ellipsis")
}
}
DefaultToolbarItem(kind: .search, placement: .bottomBar)
ToolbarSpacer(.fixed, placement: .bottomBar)
ToolbarItem(placement: .bottomBar) {
Button {
print("Add tapped")
} label: {
Label("Add", systemImage: "plus")
}
}
}
}
}
}
I present a view in a sheet that consists of a navigation stack and a scroll view which has a photo pushed to the top by setting .ignoresSafeArea(edges: .top). The problem is the top of the photo is blurry due to the scroll edge effect. I would like to hide the scroll edge effect so the photo is fully visible when scrolled to the top but let the effect become visible upon scrolling down. Is that possible?
struct ContentView: View {
@State private var showingSheet = false
var body: some View {
VStack {
Button("Present Sheet") {
showingSheet = true
}
}
.sheet(isPresented: $showingSheet) {
SheetView()
}
}
}
struct SheetView: View {
@Environment(\.dismiss) private var dismiss
var body: some View {
NavigationStack {
ScrollView {
VStack {
Image("Photo")
.resizable()
.scaledToFill()
}
}
.ignoresSafeArea(edges: .top)
.toolbar {
ToolbarItem(placement: .cancellationAction) {
Button(role: .close) {
dismiss()
}
}
ToolbarItem {
EditButton()
}
}
}
}
}
When compiled on Xcode 16.4.0:
When compiled on Xcode 26:
The code:
import SwiftUI
struct SearchBarController: UIViewRepresentable {
@Binding var text: String
var placeholderText: String
class Coordinator: NSObject, UISearchBarDelegate {
@Binding var text: String
init(text: Binding<String>) {
_text = text
}
func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
text = searchText
}
}
func makeUIView(context: Context) -> UISearchBar {
let searchBar = UISearchBar(frame: .zero)
searchBar.delegate = context.coordinator
searchBar.placeholder = placeholderText
searchBar.searchBarStyle = .minimal
return searchBar
}
func updateUIView(_ uiView: UISearchBar, context: Context) {
uiView.text = text
}
func makeCoordinator() -> SearchBarController.Coordinator {
return Coordinator(text: $text)
}
}
We have used searchable modifier with automatic or toolbar placement. When user tap on keyboard's search button it doesn't trigger onSubmit modifier.
However if placement is navigationBarDrawer it is working fine.
.searchable(text: $searchText, placement: .automatic, prompt: "Search")
.onSubmit(of: .search) {
print("Search submitted")
}
Hello Apple Developer Community: I have a problem with the fullscreencover. I can see the Things, that shouldn’t be visible behind it.
I’m currently developing with iOS 26 and only there it happens.
I hope you can help me :)
Have a nice day