I added a canvas view using PDFPageOverlayViewProvider. When I zoom the PDFView, the drawing is scaled, but its quality becomes blurry. How can I fix this?
import SwiftUI
import PDFKit
import PencilKit
import CoreGraphics
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("fail")
}
}
}
#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
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 result = UIView()
let canvasView = PKCanvasView()
canvasView.drawingPolicy = .anyInput
canvasView.tool = PKInkingTool(.pen, color: .blue, width: 20)
canvasView.translatesAutoresizingMaskIntoConstraints = false
result.addSubview(canvasView)
NSLayoutConstraint.activate([
canvasView.leadingAnchor.constraint(equalTo: result.leadingAnchor),
canvasView.trailingAnchor.constraint(equalTo: result.trailingAnchor),
canvasView.topAnchor.constraint(equalTo: result.topAnchor),
canvasView.bottomAnchor.constraint(equalTo: result.bottomAnchor)
])
for subView in view.documentView?.subviews ?? [] {
subView.isUserInteractionEnabled = true
}
result.layoutIfNeeded()
return result
}
}
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.
Selecting any option will automatically load the page
Post
Replies
Boosts
Views
Activity
I have a uisegmentedcontrol used as a customview on a right uibarbuttonitem. It has two segments. With iOS26, no matter where I tap it, it always triggers the first segment.
This worked fine in ios18.
Topic:
UI Frameworks
SubTopic:
UIKit
This is obviously a user error, but I've been working on different possibilities for a couple of days and nothing works. The problem is my Section in the following code doesn't expand or collapse when I click on the chevron:
`class AstroCat {
var title: String
var contents: [ String ]
var isExpanded: Bool
init(title: String, contents: [String], isExpanded: Bool) {
self.title = title
self.contents = contents
self.isExpanded = isExpanded
}
}
struct TestView: View {
@Binding var isShowingTargetSelection: Bool
@State var catalog: AstroCat
@State private var expanded = false
var body: some View {
NavigationStack {
List {
Section(catalog.title, isExpanded: $catalog.isExpanded) {
ForEach(catalog.contents, id: \.self) { object in
Text(object)
}
}
}
.navigationTitle("Target")
.listStyle(.sidebar)
}
}
}
#Preview {
struct TestPreviewContainer : View {
@State private var value = false
@State var catalog = AstroCat(title: "Solar System", contents: ["Sun", "Mercury", "Venus", "Earth"], isExpanded: true)
var body: some View {
TestView(isShowingTargetSelection: $value, catalog: catalog)
}
}
return TestPreviewContainer()
}`
If I change the "isExpanded: $catalog.isExpanded" to just use the local variable "expanded", then it works, so I think I have the basic SwiftUI pieces correct. But using a boolean inside of the class doesn't seem to work (the section just remains expanded or collapsed based on the initial value of the class variable).
Any hints? Am I not specifying the binding correctly? (I've tried a bunch of alternatives)
Thanks for the help,
Robert
In TabView, when I open a view in a Tab, and I switch to another Tab, but the View lifecycle of the view in the old Tab is still not over, and the threads of some functions are still in the background. I want to completely end the View lifecycle of the View in the previously opened tab when switching Tab. How can I do it? Thank you!
I work on a universal app that targets both iPhone and iPad. Our iPad app currently requires full screen. When testing on the latest iPadOS 26 beta, we see the following warning printed to the console:
Update the Info.plist: 1) `UIRequiresFullScreen` will soon be ignored. 2) Support for all orientations will soon be required.
It will take a fair amount of effort to update our app to properly support presentation in a resizable window. We wanted to gauge how urgent this change is. Our testing has shown that iPadOS 26 supports our app in a non-resizable window.
Can someone from Apple provide any guidance as to how soon “soon” is? Will UIRequiresFullScreen be ignored in iPadOS 26? Will support for all orientations be required in iPadOS 26?
My view structure in UIKit is like this: UITabBarController (with UITabBar) -> UINavigationController -> UIToolbar (by setting self.navigationController.toolbarHidden = NO). The toolbar is shown in red in the picture. I'm using it like so:
self.navigationController.toolbarHidden = NO;
self.toolbarItems = @[element1, element2];
This toolbar does work fine up to iOS 18.5 but it does not show up when compiling using iOS 26 Beta 3. Is this a bug?
I don't see any deprecation in the documentation about it. Am I doing something wrong?
Project minimum iOS deployment is set to 16.4. When running this simple code in console we receive "Observation tracking feedback loop detected!" and map is unusable.
Run code:
Map(coordinateRegion: .constant(.init()))
Console report:
...
Observable object key path '\_UICornerProvider.<computed 0x00000001a2768bc0 (Optional<UICoordinateSpace>)>' changed; performing invalidation for [layout] of: <_TtGC7SwiftUI21UIKitPlatformViewHostGVS_P10$1a57c8f9c32PlatformViewRepresentableAdaptorGV15_MapKit_SwiftUI8_MapViewGSaVS2_P10$24ce3fc8014AnnotationData____: 0x10acc2d00; baseClass = _TtGC5UIKit22UICorePlatformViewHostGV7SwiftUIP10$1a57c8f9c32PlatformViewRepresentableAdaptorGV15_MapKit_SwiftUI8_MapViewGSaVS3_P10$24ce3fc8014AnnotationData____; frame = (0 0; 353 595); anchorPoint = (0, 0); tintColor = UIExtendedSRGBColorSpace 0.333333 0.333333 0.333333 1; layer = <CALayer: 0x12443a430>>
Observable object key path '\_UICornerProvider.<computed 0x00000001a2768bc0 (Optional<UICoordinateSpace>)>' changed; performing invalidation for [layout] of: <_MapKit_SwiftUI._SwiftUIMKMapView: 0x10ae8ce00; frame = (0 0; 353 595); clipsToBounds = YES; autoresize = W+H; layer = <CALayer: 0x113beb7e0>>
Observable object key path '\_UICornerProvider.<computed 0x00000001a2768bc0 (Optional<UICoordinateSpace>)>' changed; performing invalidation for [layout] of: <_MapKit_SwiftUI._SwiftUIMKMapView: 0x10ae8ce00; frame = (0 0; 353 595); clipsToBounds = YES; autoresize = W+H; layer = <CALayer: 0x113beb7e0>>
Observable object key path '\_UICornerProvider.<computed 0x00000001a2768bc0 (Optional<UICoordinateSpace>)>' changed; performing invalidation for [layout] of: <_MapKit_SwiftUI._SwiftUIMKMapView: 0x10ae8ce00; frame = (0 0; 353 595); clipsToBounds = YES; autoresize = W+H; layer = <CALayer: 0x113beb7e0>>
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 [layout] invalidations: <_TtGC7SwiftUI21UIKitPlatformViewHostGVS_P10$1a57c8f9c32PlatformViewRepresentableAdaptorGV15_MapKit_SwiftUI8_MapViewGSaVS2_P10$24ce3fc8014AnnotationData____: 0x10acc2d00; baseClass = _TtGC5UIKit22UICorePlatformViewHostGV7SwiftUIP10$1a57c8f9c32PlatformViewRepresentableAdaptorGV15_MapKit_SwiftUI8_MapViewGSaVS3_P10$24ce3fc8014AnnotationData____; frame = (0 0; 353 595); anchorPoint = (0, 0); tintColor = UIExtendedSRGBColorSpace 0.333333 0.333333 0.333333 1; layer = <CALayer: 0x12443a430>>
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 [layout] invalidations: <_MapKit_SwiftUI._SwiftUIMKMapView: 0x10ae8ce00; frame = (0 0; 353 595); clipsToBounds = YES; autoresize = W+H; layer = <CALayer: 0x113beb7e0>>
IDE: Xcode 26 Beta 3
Testing device: iPhone 15 Pro iOS 26 Beta 3
MacOS: Tahoe 26 Beta 3
When integrating the Automatic Sign-In API on physical devices (iPhone SE with iOS 26.0 and Apple TV with tvOS 26.0), the call to requestAutoSignInAuthorization() results in an immediate error stating "Service temporarily unavailable." This prevents the app from obtaining the necessary authorization context to proceed with token updates and the Automatic Sign-In flow.
The issue occurs specifically at the authorization request stage and does not progress to calling updateAutoSignInToken(), since it does not acquire conditions for it. All entitlement and sandbox setup have been verified and are correctly configured.
Error:
Error Domain=VSErrorDomain Code=3 "The service is temporarily unavailable." UserInfo={NSLocalizedDescription=The service is temporarily unavailable., NSLocalizedRecoverySuggestion=Please try again later.}
Topic:
UI Frameworks
SubTopic:
General
Although it doesn't seem to be a forbidden practice, placing toolbar items in the bottom bar of a modal Sheet (which has its own NavigationStack) triggers massive layout warnings.
The same thing occurs when using the .searchable(...) view modifier inside a Sheet (which affects the bottom bar too).
LayoutWarning.txt
I want to make an agent application in SwiftUI.
It would be setup as a login item and have no dock icon and display no windows on start.
I used AlertScene at first, but it is unavailable on macOS 14 which is my deployment target.
Is there a way to have no windows or I'd better use AppKit for that?
Before I file a bug report I wanted to verify that I'm not missing something.
If I setup a view controller in a navigation controller and I add a view with a constraint that lines it up with the view controller's view's layoutMarginsGuide (leadingAnchor or trailingAnchor), in several cases the view will not line up with buttons added in the navigation bar. Under iOS 18 everything lines up as expected.
To demonstrate, create a new iOS project based on Swift/Storyboard. Setup the storyboard to show a UINavigationController with one UIViewController. Then in ViewController.swift (the one embedded in the navigation controller), use the following code:
import UIKit
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .yellow
title = "Layout Margins"
let leftCancel = UIBarButtonItem(systemItem: .cancel)
navigationItem.leftBarButtonItem = leftCancel
let rightCancel = UIBarButtonItem(systemItem: .cancel)
navigationItem.rightBarButtonItem = rightCancel
let leftView = UIView()
leftView.backgroundColor = .blue
leftView.translatesAutoresizingMaskIntoConstraints = false
self.view.addSubview(leftView)
let rightView = UIView()
rightView.backgroundColor = .red
rightView.translatesAutoresizingMaskIntoConstraints = false
self.view.addSubview(rightView)
NSLayoutConstraint.activate([
leftView.widthAnchor.constraint(equalToConstant: 80),
leftView.heightAnchor.constraint(equalToConstant: 80),
leftView.leadingAnchor.constraint(equalTo: self.view.layoutMarginsGuide.leadingAnchor),
leftView.topAnchor.constraint(equalTo: self.view.layoutMarginsGuide.topAnchor),
rightView.widthAnchor.constraint(equalToConstant: 80),
rightView.heightAnchor.constraint(equalToConstant: 80),
rightView.trailingAnchor.constraint(equalTo: self.view.layoutMarginsGuide.trailingAnchor),
rightView.topAnchor.constraint(equalTo: self.view.layoutMarginsGuide.topAnchor),
])
}
}
This adds a "Cancel" button to both ends of the navigation bar and it adds two little square views lined up with the leading and trailing layout margins.
Here's the results:
iPad running iPadOS 26 beta 3 (note the misalignment). This is really jarring when trying to align another glass button below the cancel button:
iPad running iPadOS 18.5 (aligned just fine):
iPhone in portrait running iOS 26 beta (aligned just fine):
iPhone in landscape running iOS 26 beta (no alignment at all):
iPhone in portrait running iOS 18.5 (aligned just fine):
iPhone in landscape running iOS 18.5 (aligned just fine):
Under iOS 26 on an iPhone (simulator at least) in portrait, the cancel buttons line up with the colored squares. That's good. In landscape, the colored squares have much larger margins as expected (due to the larger safe areas caused by the notch), but the cancel buttons in the navigation bar are not using the same margins. This one is debatable. Under iOS 18 the cancel buttons use larger margins to match the larger safe area. But I can see why under iOS 26 they changed this since the navigation bar doesn't interfere with the notch. But it's inconsistent.
Under iOS 26 on an iPad (simulator at least), it's wrong in any orientation. Despite the lack of any notch or need for a larger safe area, the colored squares are indented just a bit more than the buttons in the navigation bar. I see no reason for this. Under iOS 18 everything lines up as expected.
My real question at this point: Is the mismatched margins on an iPad under iOS 26 between the buttons in the navigation bar and other views added to the view controller a likely bug or am I missing something?
[Submitted as FB18870294, but posting here for visibility.]
In iOS 26 beta 3 (23A5287g), implicit animations no longer work when conditionally showing or hiding rows in a Form.
Rows with Text or other views inside a Section appear and disappear abruptly, even when wrapped in withAnimation or using .animation() modifiers. This is a regression from iOS 18.5, where the row item animates in and out correctly with the same code.
Repro Steps
Create a new iOS App › SwiftUI project.
Replace its ContentView struct with the code below
Build and run on an iOS 18 device.
Tap the Show Middle Row toggle and note how the Middle Row animates.
Build and run on an iOS 26 beta 3 device.
Tap the Show Middle Row toggle.
Expected
Middle Row item should smoothly animate in and out as it does on iOS 18.
Actual
Middle Row item appears and disappears abruptly, without any animation.
Code
struct ContentView: View {
@State private var showingMiddleRow = false
var body: some View {
Form {
Section {
Toggle(
"Show **Middle Row**",
isOn: $showingMiddleRow.animation()
)
if showingMiddleRow {
Text("Middle Row")
}
Text("Last Row")
}
}
}
}
Does anyone have any documentation for how to achieve the floating search tab item in UIKit apps that use UITabBarController?
The Liquid Glass UIKit video had code for minimizing the tab bar on scroll down, but I didn't see anything on keeping the search button locked to the bottom trailing edge (as in this screenshot below).
I'm developing software that implements functionality for third party touch screens. It provides features such as having touch gestures trigger mouse clicks and drags, among other possible actions.
One of its features allows keyboard focus to return to whichever app originally had it prior to performing a touch gesture. Previously it worked by recording the current frontmost app when a touch action starts, and then when all touch actions have concluded, calling NSRunningApplication.activateWithOptions and passing NSApplicationActivateIgnoringOtherApps.
However, in macOS 14 and later, this no longer works, as NSRunningApplication.activateWithOptions is deprecated. The new API provides a way for the current frontmost app to yield frontmost to whichever app is being activated with the new functions NSRunningApplication.yieldActivationToApplication and NSRunningApplication.activate, but in my case it just silently fails, presumably because my app in that moment is not frontmost. (However there is no error code provided for me to be able to find out what exactly the issue is.)
Is there a supported way I can fix this feature in macOS 14 and later?
I use the following code to keep the mouse cursor within the bounds of my application window. This causes the mouse cursor to become magnified while hugging the window's edges. Is there a way to prevent this?
My clients are building a game, board style with a large map viewed from a top camera. They want the map to pan automatically when the mouse reaches the edge of the window. And they want the mouse cursor to stay confined to the game window.
Thank you.
CGDisplayMoveCursorToPoint(CGMainDisplayID(), location);
// Removes a delay introduced by CGWarpMouseCursorPosition to keep mouse cursor motion fluid while hugging the screen edges
CGEventSourceRef eventSourceRef = CGEventSourceCreate(kCGEventSourceStateCombinedSessionState);
CGEventSourceSetLocalEventsSuppressionInterval(eventSourceRef, 0);
Hi,
I’m using SwiftUI’s Map with custom Annotation content and trying to make the annotation view ignore touch interactions—similar to applying .allowsHitTesting(false) on regular views.
The goal is to ensure that map gestures such as long press and drag are not blocked by annotation content. However, setting .allowsHitTesting(false) on the annotation content doesn’t seem to have any effect.
Is there any workaround or supported approach to allow the map to receive gestures even when they originate from annotation views?
Thanks in advance for any guidance!
In out project, we are creating a modular architecture where each module conform to certain protocol requirements for displaying the UI.
For example:
public protocol ModuleProviding: Sendable {
associatedtype Content: View
/// Creates and returns the main entry point view for this module
/// - Parameter completion: Optional closure to be called when the flow completes
/// - Returns: The main view for this module
@MainActor
func createView(_ completion: (() -> Void)?) -> Content
}
This protocol can be implemented by all different modules in the app, and I use a ViewProvider structure to build the UI from the module provided:
public struct ViewProvider: Equatable {
let id = UUID()
let provider: any ModuleProviding
let completion: () -> Void
public init(provider: any ModuleProviding, completion: @escaping () -> Void) {
self.provider = provider
self.completion = completion
}
@MainActor
public func layoutUI() -> some View {
provider.createView(completion)
}
This code throws an error:
Type 'any View' cannot conform to 'View'
To solve this error, there are two ways, one is to wrap it in AnyView, which I don't want to do.
The other option is to type check the provider with its concrete type:
@ViewBuilder @MainActor
private func buildViewForProvider(_ provider: any ModuleProviding, completion: (() -> Void)?) -> some View {
switch provider {
case let p as LoginProvider:
p.createView(completion)
case let p as PostAuthViewProvider:
p.createView(completion)
case let p as OnboardingProvider:
p.createView(completion)
case let p as RewardsProvider:
p.createView(completion)
case let p as SplashScreenProvider:
p.createView(completion)
default:
EmptyView()
}
}
This approach worked, but it defeats the purpose of using protocols and it is not scalable anymore.
Are there any other approaches I can look at ? Or is this limitation in SwiftUI ?
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
Text(...).textSelection(.enabled) does not work on iPhone and iPad, but works on Mac.
Topic:
UI Frameworks
SubTopic:
SwiftUI
I need a layout where I have a ScrollView with some content, and ScrollView has full screen background image. Screen is pushed as detail on stack.
When my screen is pushed we display navigation bar. We want a new scrollEdgeEffectStyle .soft style work. But when we scroll the gradient blur effect bellow bars is fixed to top and bottom part of the scroll view background image and is not transparent. However when content underneath navigation bar is darker and navigation bar changes automatically to adapt content underneath the final effect looks as expected doesn't use background image.
Expected bahaviour for us is that the effect under the navigation bar would not use background image but would be transparent based on content underneath.
This is how it is intialy when user didn't interact with the screen:
This is how it looks when user scrolls down:
This is how it looks when navigation bar adapts to dark content underneath:
Minimal code to reproduce this behaviour:
import SwiftUI
@main
struct SwiftUIByExampleApp: App {
var body: some Scene {
WindowGroup {
ContentView()
}
}
}
struct ContentView: View {
var body: some View {
NavigationStack {
ScrollView(.vertical) {
VStack(spacing: 0.0) {
ForEach(1 ..< 101, id: \.self) { i in
HStack {
Text("Row \(i)")
Spacer()
}
.frame(height: 50)
.background(Color.random)
}
}
}
.scrollEdgeEffectStyle(.soft, for: .all)
.scrollContentBackground(.hidden)
.toolbar {
ToolbarItem(placement: .title) {
Label("My Awesome App", systemImage: "sparkles")
.labelStyle(.titleAndIcon)
}
}
.toolbarRole(.navigationStack)
.background(
ZStack {
Color.white
.ignoresSafeArea()
Image(.sea)
.resizable()
.ignoresSafeArea()
.scaledToFill()
}
)
}
}
}
extension Color {
static var random: Color {
Color(
red: .random(in: 0...1),
green: .random(in: 0...1),
blue: .random(in: 0...1)
)
}
}
We've also tried using ZStack instead of .background modifier but we observed the same results.
We want to basically achieve the same effect as showcased here, but with the static background image:
https://youtu.be/3MugGCtm26A?si=ALG29NqX1jAMacM5&t=634