Construct and manage graphical, event-driven user interfaces for iOS or tvOS apps using UIKit.

UIKit Documentation

Posts under UIKit subtopic

Post

Replies

Boosts

Views

Activity

iPhone Duo: Making a custom popup avoid the hinge by presenting it as an arrowless popover
Background On iPhone Duo, when the device is unfolded and then partially folded, system alerts (UIAlertController) are automatically repositioned so they stay clear of the hinge. Apple's Tech Talk confirms this: "The system automatically repositions components around the reserved region." Our app uses a custom popup: a view controller presented with .overFullScreen that lays out its own dimming view and a custom-drawn view (here, a coupon ticket with notched edges) in the center of the screen. This popup is not repositioned. It stays centered on screen, right on top of the fold. The recommended approach for custom UI is to query view.reservedRegions(kind: .division) and lay out around the fold manually. Before going that route, I tried something simpler. What I tried The Tech Talk lists popovers among the components the system repositions. So I presented the same custom view as a popover with no arrow, anchored to the center of the presenting view: final class CouponPopoverViewController: UIViewController, UIPopoverPresentationControllerDelegate { private let ticketView = CouponTicketView() // the custom popup view init(centeredIn sourceView: UIView) { super.init(nibName: nil, bundle: nil) modalPresentationStyle = .popover guard let popover = popoverPresentationController else { return } popover.sourceView = sourceView popover.sourceRect = Self.centerPoint(of: sourceView.bounds) popover.permittedArrowDirections = [] // Drop the system popover chrome so only the custom view (and its own shadow) is visible. popover.popoverBackgroundViewClass = ClearPopoverBackgroundView.self popover.delegate = self } required init?(coder: NSCoder) { fatalError() } override func viewDidLoad() { super.viewDidLoad() view.backgroundColor = .clear ticketView.translatesAutoresizingMaskIntoConstraints = false view.addSubview(ticketView) NSLayoutConstraint.activate([ ticketView.topAnchor.constraint(equalTo: view.topAnchor), ticketView.bottomAnchor.constraint(equalTo: view.bottomAnchor), ticketView.leadingAnchor.constraint(equalTo: view.leadingAnchor), ticketView.trailingAnchor.constraint(equalTo: view.trailingAnchor) ]) preferredContentSize = ticketView.systemLayoutSizeFitting( CGSize(width: 300, height: UIView.layoutFittingCompressedSize.height), withHorizontalFittingPriority: .required, verticalFittingPriority: .fittingSizeLevel ) } private static func centerPoint(of bounds: CGRect) -> CGRect { CGRect(x: bounds.midX, y: bounds.midY, width: 0, height: 0) } // Keep it a popover on iPhone instead of adapting to a sheet. func adaptivePresentationStyle(for controller: UIPresentationController, traitCollection: UITraitCollection) -> UIModalPresentationStyle { .none } // Re-anchor to the center after rotation or fold changes. func popoverPresentationController(_ popoverPresentationController: UIPopoverPresentationController, willRepositionPopoverTo rect: UnsafeMutablePointer<CGRect>, in view: AutoreleasingUnsafeMutablePointer<UIView>) { rect.pointee = Self.centerPoint(of: view.pointee.bounds) } } /// A popover background that draws nothing: no arrow, no insets, no default appearance. final class ClearPopoverBackgroundView: UIPopoverBackgroundView { override class func arrowBase() -> CGFloat { 0 } override class func arrowHeight() -> CGFloat { 0 } override class func contentViewInsets() -> UIEdgeInsets { .zero } override class var wantsDefaultContentAppearance: Bool { false } override var arrowOffset: CGFloat { get { 0 } set {} } override var arrowDirection: UIPopoverArrowDirection { get { .any } set {} } } Result Partially folded, portrait (hinge runs horizontally across the middle of the screen): Before: the custom popup (.overFullScreen) stays centered, right across the hinge. After: the same view presented as an arrowless popover moves into the top half, clear of the hinge. Partially folded, book pose (vertical hinge): the popover moves to the leading page, clear of the hinge. This matches where a system UIAlertController goes in the same pose. I also checked that the popover shows correctly on the outer display (closed) and on a non-Duo iPhone (iPhone 18 Pro, iOS 27.0). Tested on: iPhone Duo simulator (iOS 27.1), Xcode 27.1 RC (27A9275) iPhone 18 Pro simulator (iOS 27.0) Things to handle when switching to a popover Tap-outside dismissal: Popovers dismiss on outside taps by default. Set isModalInPresentation = true or return false from presentationControllerShouldDismiss(_:) if the popup should only close via its buttons. Dimming: Popovers don't dim the background like a typical custom popup (compare the before and after screenshots). Add your own dimming view if needed. Chrome: By default, the system draws its own background behind the content. For a custom-shaped view, this shows through any transparent areas and clips the view's shadow. A UIPopoverBackgroundView subclass that draws nothing (above) removes it. Sizing: Set preferredContentSize explicitly. Recompute it for dynamic content and Dynamic Type. Questions This works well in my testing, but I couldn't find any documentation saying that an arrowless popover anchored to the center gets the same hinge avoidance as alerts. Is this supported behavior that we can rely on going forward? Or is reservedRegions(kind:options:) with manual layout the only recommended approach for custom popups? It would also be great to have a public API that lets custom presentations opt into the same hinge-avoidance placement that system alerts use. Hope this helps anyone else dealing with custom popups on iPhone Duo.
Topic: UI Frameworks SubTopic: UIKit Tags:
2
0
78
11h
iPhone Duo - Current SDK State
We are just 9 days before the iPhone Duo release, and the SDK is still in a pretty bad state, at least for the Keyboard Extension: Hinge detection doesn't work Reserved area detection doesn't work needsInputModeSwitchKey returns false even though iOS doesn't display its own globe button Switching between closed and fully open state loses text field focus and the keyboard disappears (regression bug - it worked in Beta 1) It's unacceptable that, with such a short release date, we still don't have a stable SDK... I expect the iPhone Duo release to be one of the buggiest releases Apple has ever done.
7
0
423
12h
UISheetPresentationController issues on iPhone Duo
I have an App where I use the UISheetPresentationController to present a menu as a "drawer" (like the "FindMy" or "Maps") App. Because the sheet is presented over a map, I made the sheet semi-transparent/blurry, so the Map shines through, which looks nice. The sheet is using a UITableView with the "insetGroup" style, so the table cells have the nice rounded borders and there are margins to the sheet borders. When running the App on the iPhone Duo (Simulator) on the outer display, the tableView does no longer respect the "insetGroup" style, it is rendered like it would have the "plain" style, which destroys everything that look good. No rounded borders, no margins. However if I opt-out of the automatic "vertical toolbar behavior" (overriding preferredVerticalBarBehavior so it returns "disabled"), then everything looks great again, however then the sheet content might overlap with the sidebar icons and camera because it now covers the whole area up to the right screen border. Is this supposed to be this way (if yes, why?), is there a way to fix this, or do we have to wait for a bugfix within iOS 27.1? The tableview still claims to have the "insetGrouped" style, just it does not render this way. I did not see any similar issues under other circumstances. Only UISheetPresentationController seems to be affected by this. Is there a way to correctly detect if the App is running on an iPhone Duo, so we could use this detection to add workarounds for such issues?
4
1
517
17h
How to get UISheetPresentationController width to adjust for vertical toolbar on iPhone Duo?
If you run Safari in the iPhone Duo simulator and choose to share something you get a screen similar to the following: In my own app, if I present a UIActivityViewController I get a similar result. Note that the share sheet does not cover the vertical toolbar at all. So my question is how to present a UISheetPresentationController to look the same way. In other words, how to get the width of the UISheetPresentationController to take into account the vertical toolbar? All of my existing code to create and present a UISheetPresentationController result in the UISheetPresentationController taking the full width of the screen. The contents of the sheet take the safe area into account, but that's not the same result. I need the sheet itself to be narrower. I don't see an API for this. Or does this require more complicated presentation controller / delegate setup? Here is some relevant code in the view controller that I want displayed in the sheet: self.modalPresentationStyle = .popover self.presentationController?.delegate = self if let sheet = popoverPresentationController?.adaptiveSheetPresentationController { popoverPresentationController?.passthroughViews = [] sheet.detents = [ .medium(), .large() ] sheet.largestUndimmedDetentIdentifier = nil sheet.prefersGrabberVisible = false sheet.prefersScrollingExpandsWhenScrolledToEdge = true sheet.prefersEdgeAttachedInCompactHeight = true sheet.widthFollowsPreferredContentSizeWhenEdgeAttached = true } Or maybe UISheetPresentationController is the wrong approach.
Topic: UI Frameworks SubTopic: UIKit Tags:
0
0
70
23h
UIAlertController.addTextField results in broken text field in 27.1
I just downloaded Xcode 27.1 to test out the iPhone Duo simulator, and I notice that UIAlertController.addTextField, which was working fine in 27, is now very broken, resulting in a text field that is squashed vertically and pushed over to the right in the alert sheet. This is very easy to reproduce - the following code will show the problem if you build in Xcode 27.1 and run on iOS 27.1 or iOS 27.2: let alert = UIAlertController(title: "Create Something", message: "Enter a title.", preferredStyle: .alert) alert.addTextField { textField in textField.placeholder = "Title" } alert.addAction(UIAlertAction(title: "Cancel", style: .cancel)) present(alert, animated: true) The bug isn't limited to the Duo, but can also be seen on an iPad (and probably a regular phone). I would post a screenshot, but the last time I tried that, the forum software erroneously banned me for two weeks. I have reported this as bug #FB24889500, but given that we use alerts with text fields for users adding new items to the outline in our app, something the user does a lot, I'm wondering if there is a workaround, since this is going to make our app look very buggy.
Topic: UI Frameworks SubTopic: UIKit Tags:
1
2
290
1d
How to preserve collection view scroll anchor when folding/unfolding iPhone Duo
The following question was asked in the Oct 13 iPhone Duo group lab: when you unfold iPhone Duo after you’ve scrolled down, does UIKit keep the position or should we re-anchor ourselves? The answer was various scroll views like collection views and text views will handle this for you to keep visible items visible, which also works when resizing the window on iPad. This is not working for me with a simple UICollectionView. What do I need to do to obtain this behavior? class ViewController: UIViewController, UICollectionViewDataSource { override func viewDidLoad() { super.viewDidLoad() let layout = UICollectionViewFlowLayout() layout.itemSize = CGSize(width: 80, height: 80) layout.minimumInteritemSpacing = 8 layout.minimumLineSpacing = 8 layout.sectionInsetReference = .fromLayoutMargins let collectionView = UICollectionView(frame: .zero, collectionViewLayout: layout) collectionView.translatesAutoresizingMaskIntoConstraints = false collectionView.backgroundColor = .systemBackground collectionView.dataSource = self collectionView.insetsLayoutMarginsFromSafeArea = true collectionView.register(UICollectionViewCell.self, forCellWithReuseIdentifier: "Cell") view.addSubview(collectionView) NSLayoutConstraint.activate([ collectionView.topAnchor.constraint(equalTo: view.topAnchor), collectionView.leadingAnchor.constraint(equalTo: view.leadingAnchor), collectionView.trailingAnchor.constraint(equalTo: view.trailingAnchor), collectionView.bottomAnchor.constraint(equalTo: view.bottomAnchor) ]) } func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { 5000 } func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "Cell", for: indexPath) var content = UIListContentConfiguration.cell() content.text = String(indexPath.item) content.textProperties.alignment = .center cell.contentConfiguration = content var background = UIBackgroundConfiguration.clear() background.backgroundColor = .secondarySystemBackground cell.backgroundConfiguration = background return cell } } Run the app on iPhone Duo Scroll down to cell 100 on the outer display Unfold the device Expected: It should stay scrolled to item 100 Actual: It scrolled down to item 225 (or more accurately, the content offset did not change, more content was added higher up with the contentSize shrinking due to the expanded width) In the past I've put so much work into trying to maintain the expected scroll position for orientation changes on iPhone and iPad/Mac Catalyst resize events, it's surprisingly incredibly hard to get working in every scenario, so I am SUPER interested to learn the system can do it for us!
0
0
82
1d
How to set custom height for keyboard extension without resize flicker?
Description I'm developing a custom keyboard extension using UIInputViewController and need to set a specific height of 268 points. The keyboard functions correctly, but there's a visible flicker and resize animation during launch that I cannot eliminate. The Problem When the keyboard launches, iOS provides incorrect heights before settling on the correct one. At launch, the view starts at 0×0. Around 295ms later, iOS sets the frame to 440×956 which is full screen height and wrong. Around 373ms, iOS changes it to 440×452 which is still wrong. Finally around 390ms, iOS settles at 440×268 which matches our constraint. This causes visible flicker as the view resizes three times rapidly. The keyboard appears to shrink from full screen down to the correct height, and users can clearly see this animation happening. What I've Tried I've tried adding a height constraint on self.view which gives me the correct height but causes the visible flicker. I created a custom UIInputView subclass and overrode intrinsicContentSize to return my desired height. iOS completely ignores this and gives random heights like 471pt, 680pt, or 956pt instead. I set allowsSelfSizing to true on my UIInputView subclass. iOS ignores this property. I set preferredContentSize on the view controller. iOS ignores this as well. I tried adding the constraint in viewDidAppear instead of viewDidLoad, thinking iOS might have settled by then. It still causes flicker. I overrode the frame and bounds setters on my UIInputView to clamp the height to my desired value. iOS bypasses these overrides somehow. I overrode layoutSubviews to force the correct height after the super call. iOS still applies its own height. Specific Question What is the correct API or technique to specify a keyboard extension's height that iOS will respect immediately upon launch, without triggering the resize animation sequence? Other third-party keyboards like Grammarly and SwiftKey appear to have solved this problem. Their keyboards appear at the correct height without any visible flicker. How do they achieve this? Expected Outcome The keyboard should appear at 268pt height on the first frame with no visible resize animation. Steps to Reproduce Create a new iOS App project in Xcode and add a Keyboard Extension target. In KeyboardViewController.swift, add a height constraint in viewDidLoad: override func viewDidLoad() { super.viewDidLoad() let heightConstraint = view.heightAnchor.constraint(equalToConstant: 268) heightConstraint.priority = .defaultHigh heightConstraint.isActive = true let label = UILabel() label.text = "Demo Keyboard" label.textAlignment = .center label.translatesAutoresizingMaskIntoConstraints = false view.addSubview(label) NSLayoutConstraint.activate([ label.centerXAnchor.constraint(equalTo: view.centerXAnchor), label.centerYAnchor.constraint(equalTo: view.centerYAnchor) ]) } Build and run on a physical device. Enable the keyboard in Settings, then General, then Keyboard, then Keyboards. Open any app with a text field and switch to the custom keyboard using the globe button. Observe the height changing from around 956pt to 452pt to 268pt with visible animation. Environment iOS 17 and iOS 18 and 26.2, Xcode 16 and Xcode 26, affects all iPhone models tested, reproducible on both simulator and physical device.
4
6
1.1k
1d
iOS 27: print(to:) silently drops every job after the first
The problem On iOS 27, UIPrintInteractionController.print(to:completionHandler:) works on its first call in a process. Every subsequent call is accepted (print(to:) returns true and printInteractionControllerWillStartJob fires), but the completion handler is never invoked: nothing prints, didFinishJob never fires, no error is produced, and no job appears in Print Center. I expected each call to submit an independent job and invoke its completion handler, as it does on iOS 26 and earlier with the identical binary. Steps to reproduce Build an app that prints without the print panel, using a retained UIPrinter from UIPrinterPickerController. Submit a job: let controller = UIPrintInteractionController.shared let info = UIPrintInfo(dictionary: nil) info.outputType = .general info.jobName = "job-\(n)" controller.printInfo = info controller.printingItem = pdfData // valid PDF, canPrint(data) == true controller.delegate = self let started = controller.print(to: savedPrinter) { _, completed, error in print("completion", completed, String(describing: error)) } print("started", started) First job: started == true, both willStartJob and didFinishJob fire, the completion handler runs with completed == true, and the page prints. Submit a second job the same way, same process. started == true and willStartJob fires with printInfo.printerID populated and printPaper negotiated to the same values as the successful job. Then nothing. No didFinishJob, no completion handler, no error, no page, nothing in Print Center. A third job: print(to:) returns false synchronously, since the shared controller still considers job two in flight. System information iPad, iPadOS 27.0 developer beta 6 Built against iOS 26.2 SDK (Xcode 26.2). Same binary works on iOS 26. Reproduced on two unrelated printers: Brother QL-820NWB and Canon MF420 Series. Content is a small PDF (~11 to 13 KB); canPrintData: returns true. Troubleshooting tried Restarted the iPad and reinstalled the app. Each buys exactly one successful print before the failure returns. Compared observable state between the working and hung jobs. Identical in every respect. During a hang, printed the same content to the same printer from Files via the share sheet. Worked normally, including on repeat. Paused in the debugger during the hang. No blocked thread; no PrintKit frame, XPC wait, or semaphore anywhere in bt all. Called contactPrinter before each job on the retained printer. Returned true quickly, and the job still hung. Implemented printInteractionControllerParentViewController(_:) in case a presentation context was missing. UIKit never calls it on this path. Workaround Creating a new UIPrintInteractionController per job resolves it completely. A long-lived instance the app creates itself fails exactly like .shared does, so the issue is reuse of a controller that has already run a job, not the shared singleton specifically. Is per-job instantiation the supported pattern? The docs say the shared instance "represents a print job" but don't state whether a controller may be reused for a second job, and every sample I can find uses sharedPrintController with the present… methods rather than print(to:).
5
7
1.2k
1d
Layout margins guides are still broken the iPhone Duo (sim) and 27.1 RC
Layout margin guides are broken throughout UIKit and SwiftUI on the iPhone Duo sim in iOS 27.1 RC. For example, a cell which looks perfectly fine on a normal iPhone sim (which has a compact horizontal size class), has zero vertical layout margins on iPhone Duo. Here's some screenshots. The red dotted lines are supposed to show the margins in the cell content view, i.e., the boundary between default padding around the cell (for its background) and the content of the cell. On every other device and size class these all work, and will have some vertical margin. iPhone 18 Pro: iPhone Duo: As you can see, the border is cut off. No vertical margins at all. iPhone Duo Unfolded: Not only is it busted just in UICollectionViews. Check out this segmented control (also configured with layout margins). This works fine on catalyst, iPhone, and iPad. This makes me very nervous about shipping with the 27.1 SDK. Is this a known issue? If so, what is the recommended workaround in the meantime? FB25097501
5
0
293
1d
UISearchBar’s delegate method searchBarCancelButtonClicked is not called on search cancel when search bar is integrated into the navigation bar on iOS 27
Hi, I would like to share an issue with UISearchBar's delegate method searchBarCancelButtonClicked on iOS 27 beta. On iOS 27 beta, when search bar is integrated into navigation bar’s items, tapping search cancel button doesn’t invoke UISearchBar’s delegate method searchBarCancelButtonClicked:. Steps to reproduce: Create UINavigationController with one UIViewController Set up searchController. Set searchController.searchBar.delegate, preferredSearchBarPlacement = .integratedButton, searchBarPlacementAllowsToolbarIntegration = false Tap the search button and type a query Tap the search cancel button Expected: On iOS 26, the searchBarCancelButtonClicked delegate method is called. Actual: On iOS 27 beta, the searchBarCancelButtonClicked delegate method is NOT called. On iOS 27 beta, if search bar is “stacked” or placed in the toolbar rather than the navigation bar, the bug does not reproduce. I’m using Xcode Version 27.0 beta 6 with latest available iOS 27 iPhone 17 Pro simulator (24A5423a). I reported the issue via Feedback Assistant with a minimal reproduction example and 2 videos comparing the behavior between iOS 26 and iOS 27 beta. Here is the report ID: FB24636315. Here is the minimal reproduction example: // SceneDelegate.swift import UIKit class SceneDelegate: UIResponder, UIWindowSceneDelegate { var window: UIWindow? func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) { guard let windowScene = scene as? UIWindowScene else { return } let window = UIWindow(windowScene: windowScene) window.rootViewController = UINavigationController(rootViewController: ViewController()) window.makeKeyAndVisible() self.window = window } } // ViewController.swift import UIKit final class ViewController: UITableViewController { private let allItems = (1...30).map { "Item \($0)" } private var items: [String] = [] private var cancelCount = 0 override func viewDidLoad() { super.viewDidLoad() items = allItems updateTitle() let searchController = UISearchController(searchResultsController: nil) searchController.searchBar.delegate = self navigationItem.searchController = searchController navigationItem.preferredSearchBarPlacement = .integratedButton navigationItem.searchBarPlacementAllowsToolbarIntegration = false tableView.register(UITableViewCell.self, forCellReuseIdentifier: "cell") } private func updateTitle() { title = "Cancel presses: \(cancelCount)" } override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { items.count } override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) cell.contentConfiguration = { var config = cell.defaultContentConfiguration() config.text = items[indexPath.row] return config }() return cell } } extension ViewController: UISearchBarDelegate { func searchBarCancelButtonClicked(_ searchBar: UISearchBar) { print("searchBarCancelButtonClicked(_:)") cancelCount += 1 updateTitle() items = allItems tableView.reloadData() } } Thank you in advance!
Topic: UI Frameworks SubTopic: UIKit Tags:
2
2
365
1d
iOS App QuickType Bar Credit Card Autofill Not Working
According to this autofill credit card documentation we should be able to autofill credit card fields using the QuickType Bar for credit card fields, but it does not work. The QuickType Bar does not display for credit card fields (see screenshots) I have tested this on a physical device running iOS 27 (iPhone 16e), have added a card to the Autofill setting in the Wallet app, and have made sure my text fields have the correct textContentType values. I am able to autofill using the backup autofill menu, but it is less than ideal. It takes a minimum of 5 taps to autofill one field. It would be far less painful to just pull out the credit card and manually enter the information (see screenshot). Here is a link to my test project demonstrating the issue: https://drive.google.com/file/d/1wMGOUNhVnmt3rBAD0TSMf9NV39-JS9ij/view?usp=sharing
1
0
286
2d
iOS 26 beta3 Custom keyboard always displays a gray bar above it
Problem description: When using the Custom keyboard in various system application scenarios, a gray area is always displayed at the top of the Custom keyboard. Although the system has been restarted and the Custom keyboard has been restarted, and the pull-down operation has been repeated in multiple system application environments, the gray bar still appears. This problem also has the same problem on other input method software. Reproduction steps: Set the current input method to "CustomKeybaord" In the memo app or any other system app, pull up the Custom keyboard, or switch to the Custom keyboard. Observe whether a gray area is always displayed above the Custom keyboard. Request: I would like to understand whether the current behavior is a bug or if it requires Custom keyboards to adapt their style accordingly. However, I not found that currently unable to modify the style or color of the gray bar in question, and I do not have a suitable adaptation solution at this time. I would appreciate further assistance
Topic: UI Frameworks SubTopic: UIKit
6
2
644
2d
External Display stops working at iOS 27 / Xcode 27
I have an app that connects to an external display, the app controls content for the external display, but the external display is not active and uses the UIWindowSceneSessionRoleExternalDisplayNonInteractive role. I migrated the app to use UIScene lifecycle last year and everything seemed to be working. I use - (UISceneConfiguration *) application:(UIApplication *) application configurationForConnectingSceneSession:(UISceneSession *) connectingSceneSession options:(UISceneConnectionOptions *) options; in the AppDelegate to provide the configurations. But now at XCode 27/ iOS 27, that code is not called when I connect the external display with a dislpay adapter to my iPhone. But the device connects and shows a mirror of my iPhone display. What's going on?
Topic: UI Frameworks SubTopic: UIKit
2
0
86
2d
Save & Edit UIBarButtonSystemItems need to be updated for the iPhone Duo
When creating a UIBarButtonItem using the standard UIBarButtonSystemItem values of UIBarButtonSystemItemSave or UIBarButtonSystemEdit you end up with text-only buttons. The text-only buttons are an issue with the iPhone Duo since such buttons do not get put in the vertical sidebar. This is a problem with a view controller with scrollable content. The text-only Save or Edit buttons can scroll out of view leaving the user confused about how to complete their work on the screen. Related is the UIViewController editButtonItem which gives the standard Edit/Done toggle button. Since the button shows the text "Edit" the button doesn't get put in the vertical sidebar. This is despite the Done display being shown as a checkmark icon.
Topic: UI Frameworks SubTopic: UIKit Tags:
1
0
375
3d
Best practice Replacement for Edit Button on iPhone Duo
On the iPhone Duo the standard "Edit" button for navigation bars is a text-based button, and text-based buttons are not pushed to the vertical toolbars on the Duo. This looks sometimes silly, if it is the only remaining button that can not be placed in the vertical toolbar and which has the result that an almost empty horizontal navigation bar must be kept visible as well. So I guess it would be good idea to have an icon-based replacement for the Editor button to avoid having two toolbars on the Duo. Is there a best practice for the icon to pick for such an edit button? Would be "square.and.pencil" (SF Symbols) a good choice? Or better the "pencil .circle", because the "square" one is often used for text-based input? Anything better?
4
0
955
3d
UITableView row reordering no longer works under macOS 27 with Mac Catalyst
Under macOS 27 using Mac Catalyst for a UIKit-based app, If you present a view controller with a table view as a form sheet or page sheet, row reordering fails to function. You can drag a row as expected but the blue movement bar never appears and if you drop the row it simply returns to its original location. The exact same view controller presented as a popover works just fine. The exact same view controller not presented as a modal (such as the app's root controller) works just fine. This is a serious bug affecting existing applications and being reported by paying customers. This has been reported as FB25038883 which includes a simple sample app demonstrating the issue.
0
0
282
3d
UINavigationController, Nav Bar buttons incorrect layout on iPhone Duo
When presenting a UINavigationController presented via UIViewControllerRepresentable in a sheet, the top nav bar buttons aren't correctly moving to the side bar on the front screen of the Duo. They do re-orient vertically, but they do so next to the side bar and not within it. What am I doing wrong? This is how I am setting the buttons: let trimButton = UIBarButtonItem(image: UIImage(systemName: "selection.pin.in.out"), style: .plain, target: self, action: #selector(enterTrimming(_:))) navigationItem.leftBarButtonItem = trimButton navigationItem.rightBarButtonItem = cancelButton navigationItem.leftBarButtonItem?.isEnabled = true navigationItem.rightBarButtonItem?.isEnabled = true
Topic: UI Frameworks SubTopic: UIKit Tags:
1
0
101
3d
How to automatically size a table's footer view
Hi, I would like to automatically vertically size the table's footer view so that it has a fixed pre-defined minimum height and maximum height that fills up the gap between the last cell and the bottom of the safe area. How can I do this? PS: It seems to be that the footer view's size is not included in the table view's content size, correct? Regards, Hardy
Topic: UI Frameworks SubTopic: UIKit Tags:
1
0
59
3d
iPhone Duo: navigation bar item briefly moves to vertical bar during fullScreen dismissal despite .disabled
On the folded iPhone Duo display, a navigation bar item briefly moves into the vertical bar during dismissal of a full-screen modal, then jumps back to the top. Both navigation controllers consistently return .disabled from preferredVerticalBarBehavior, with childForPreferredVerticalBarBehavior returning nil. Environment Xcode 27.1 RC (27A9275), iOS 27.1 SDK, iPhone Duo simulator, folded outer display in portrait. Steps to reproduce Run the single-file UIKit example below in a scene-based app with a generated launch screen and no main storyboard. Tap the gear button on the Home screen to present Settings using .fullScreen. Tap the close button on Settings. Watch the Home screen's gear button during the dismissal animation. Expected The gear button stays in the top horizontal navigation bar throughout the transition, because the vertical bar preference is .disabled on both navigation controllers. Actual For part of the dismissal, the gear button appears below the status icons in the right-hand vertical bar region. It then jumps back to the top horizontal bar. The underlying tab bar also temporarily moves from the bottom to the right before returning. This reproduces with an otherwise empty view, standard UIKit containers, and the default bar appearance. No app code changes safeAreaInsets, bar frames, or animation timing. During the presentation/dismissal cycle, the Home view's logged right safe-area inset changes from 0 to 88 points and back to 0. In our app, content constrained to the safe area visibly narrows during the same transient change. In separate comparisons, returning .disabled from the root tab controller and content controllers, or requesting setNeedsUpdateOfVerticalBarConfiguration in appearance callbacks, did not eliminate the issue. Changing the modal to .overFullScreen avoided it in the tested simulator, but changes the underlying view controller lifecycle. The example below intentionally keeps .fullScreen to reproduce the problem. Is this expected behavior, or a known UIKit issue? Is there a supported way to keep .disabled effective throughout a fullScreen presentation/dismissal? Has this been addressed in a newer SDK/runtime? I have not tested iOS 27.2 or a physical Duo device. Minimal reproduction (one Swift file): import UIKit @main final class DemoAppDelegate: UIResponder, UIApplicationDelegate { func application(_ application: UIApplication, configurationForConnecting session: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration { let configuration = UISceneConfiguration(name: "Demo", sessionRole: session.role) configuration.delegateClass = DemoSceneDelegate.self return configuration } } final class DemoSceneDelegate: UIResponder, UIWindowSceneDelegate { var window: UIWindow? func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options: UIScene.ConnectionOptions) { guard let scene = scene as? UIWindowScene else { return } let home = DemoController() home.title = "首页" let navigation = DemoNavigationController(rootViewController: home) navigation.tabBarItem = UITabBarItem(title: "首页", image: UIImage(systemName: "house"), selectedImage: nil) let tabs = UITabBarController() if #available(iOS 18.0, *) { tabs.mode = .tabBar } tabs.viewControllers = [navigation] let window = UIWindow(windowScene: scene) window.rootViewController = tabs self.window = window window.makeKeyAndVisible() } } final class DemoNavigationController: UINavigationController { // 与音剪一致:导航容器固定横向栏,不转发给子页面。 @available(iOS 27.1, *) override var preferredVerticalBarBehavior: UIVerticalBarBehavior { .disabled } @available(iOS 27.1, *) override var childForPreferredVerticalBarBehavior: UIViewController? { nil } } final class DemoController: UIViewController { override func viewDidLoad() { super.viewDidLoad() view.backgroundColor = .systemBackground if title == "设置" { navigationItem.leftBarButtonItem = UIBarButtonItem(systemItem: .close, primaryAction: UIAction { [weak self] _ in self?.dismiss(animated: true) }) } else { navigationItem.rightBarButtonItem = UIBarButtonItem( image: UIImage(systemName: "gearshape"), primaryAction: UIAction { [weak self] _ in let settings = DemoController() settings.title = "设置" let navigation = DemoNavigationController(rootViewController: settings) navigation.modalPresentationStyle = .fullScreen self?.present(navigation, animated: true) }) } } override func viewDidLayoutSubviews() { super.viewDidLayoutSubviews() print("[DuoDemo] \(title ?? "") safe=\(view.safeAreaInsets) nav=\(navigationController?.navigationBar.frame ?? .zero) tab=\(tabBarController?.tabBar.frame ?? .zero)") } }
0
0
191
3d
UIScreen.screens.count differs on iPhone Duo sims depending on if app is IOS 26 SDK, or iOS 27 SDK
Hi there, My app uses UIScreen.screens.count (deprecated) to predict whether mirroring is happening on older iOS devices I noticed that the number of screens is different between iOS 26 SDK apps, and iOS 27 SDK apps. Can I expect that iOS 26 SDK apps will continue to return 1 screen like below for the iPhone Duo release?. I assume it's like this is to maximise compatibility. App built with SDK 26 on Xcode 27.1b1 iPhone Duo sim: UIScreen.screens.count == 1 App built with SDK 27 on Xcode 27.1b1 iPhone Duo sim: UIScreen.screens.count == 2 Thanks for the help! Sam
Topic: UI Frameworks SubTopic: UIKit Tags:
4
0
293
3d
iPhone Duo: Making a custom popup avoid the hinge by presenting it as an arrowless popover
Background On iPhone Duo, when the device is unfolded and then partially folded, system alerts (UIAlertController) are automatically repositioned so they stay clear of the hinge. Apple's Tech Talk confirms this: "The system automatically repositions components around the reserved region." Our app uses a custom popup: a view controller presented with .overFullScreen that lays out its own dimming view and a custom-drawn view (here, a coupon ticket with notched edges) in the center of the screen. This popup is not repositioned. It stays centered on screen, right on top of the fold. The recommended approach for custom UI is to query view.reservedRegions(kind: .division) and lay out around the fold manually. Before going that route, I tried something simpler. What I tried The Tech Talk lists popovers among the components the system repositions. So I presented the same custom view as a popover with no arrow, anchored to the center of the presenting view: final class CouponPopoverViewController: UIViewController, UIPopoverPresentationControllerDelegate { private let ticketView = CouponTicketView() // the custom popup view init(centeredIn sourceView: UIView) { super.init(nibName: nil, bundle: nil) modalPresentationStyle = .popover guard let popover = popoverPresentationController else { return } popover.sourceView = sourceView popover.sourceRect = Self.centerPoint(of: sourceView.bounds) popover.permittedArrowDirections = [] // Drop the system popover chrome so only the custom view (and its own shadow) is visible. popover.popoverBackgroundViewClass = ClearPopoverBackgroundView.self popover.delegate = self } required init?(coder: NSCoder) { fatalError() } override func viewDidLoad() { super.viewDidLoad() view.backgroundColor = .clear ticketView.translatesAutoresizingMaskIntoConstraints = false view.addSubview(ticketView) NSLayoutConstraint.activate([ ticketView.topAnchor.constraint(equalTo: view.topAnchor), ticketView.bottomAnchor.constraint(equalTo: view.bottomAnchor), ticketView.leadingAnchor.constraint(equalTo: view.leadingAnchor), ticketView.trailingAnchor.constraint(equalTo: view.trailingAnchor) ]) preferredContentSize = ticketView.systemLayoutSizeFitting( CGSize(width: 300, height: UIView.layoutFittingCompressedSize.height), withHorizontalFittingPriority: .required, verticalFittingPriority: .fittingSizeLevel ) } private static func centerPoint(of bounds: CGRect) -> CGRect { CGRect(x: bounds.midX, y: bounds.midY, width: 0, height: 0) } // Keep it a popover on iPhone instead of adapting to a sheet. func adaptivePresentationStyle(for controller: UIPresentationController, traitCollection: UITraitCollection) -> UIModalPresentationStyle { .none } // Re-anchor to the center after rotation or fold changes. func popoverPresentationController(_ popoverPresentationController: UIPopoverPresentationController, willRepositionPopoverTo rect: UnsafeMutablePointer<CGRect>, in view: AutoreleasingUnsafeMutablePointer<UIView>) { rect.pointee = Self.centerPoint(of: view.pointee.bounds) } } /// A popover background that draws nothing: no arrow, no insets, no default appearance. final class ClearPopoverBackgroundView: UIPopoverBackgroundView { override class func arrowBase() -> CGFloat { 0 } override class func arrowHeight() -> CGFloat { 0 } override class func contentViewInsets() -> UIEdgeInsets { .zero } override class var wantsDefaultContentAppearance: Bool { false } override var arrowOffset: CGFloat { get { 0 } set {} } override var arrowDirection: UIPopoverArrowDirection { get { .any } set {} } } Result Partially folded, portrait (hinge runs horizontally across the middle of the screen): Before: the custom popup (.overFullScreen) stays centered, right across the hinge. After: the same view presented as an arrowless popover moves into the top half, clear of the hinge. Partially folded, book pose (vertical hinge): the popover moves to the leading page, clear of the hinge. This matches where a system UIAlertController goes in the same pose. I also checked that the popover shows correctly on the outer display (closed) and on a non-Duo iPhone (iPhone 18 Pro, iOS 27.0). Tested on: iPhone Duo simulator (iOS 27.1), Xcode 27.1 RC (27A9275) iPhone 18 Pro simulator (iOS 27.0) Things to handle when switching to a popover Tap-outside dismissal: Popovers dismiss on outside taps by default. Set isModalInPresentation = true or return false from presentationControllerShouldDismiss(_:) if the popup should only close via its buttons. Dimming: Popovers don't dim the background like a typical custom popup (compare the before and after screenshots). Add your own dimming view if needed. Chrome: By default, the system draws its own background behind the content. For a custom-shaped view, this shows through any transparent areas and clips the view's shadow. A UIPopoverBackgroundView subclass that draws nothing (above) removes it. Sizing: Set preferredContentSize explicitly. Recompute it for dynamic content and Dynamic Type. Questions This works well in my testing, but I couldn't find any documentation saying that an arrowless popover anchored to the center gets the same hinge avoidance as alerts. Is this supported behavior that we can rely on going forward? Or is reservedRegions(kind:options:) with manual layout the only recommended approach for custom popups? It would also be great to have a public API that lets custom presentations opt into the same hinge-avoidance placement that system alerts use. Hope this helps anyone else dealing with custom popups on iPhone Duo.
Topic: UI Frameworks SubTopic: UIKit Tags:
Replies
2
Boosts
0
Views
78
Activity
11h
iPhone Duo - Current SDK State
We are just 9 days before the iPhone Duo release, and the SDK is still in a pretty bad state, at least for the Keyboard Extension: Hinge detection doesn't work Reserved area detection doesn't work needsInputModeSwitchKey returns false even though iOS doesn't display its own globe button Switching between closed and fully open state loses text field focus and the keyboard disappears (regression bug - it worked in Beta 1) It's unacceptable that, with such a short release date, we still don't have a stable SDK... I expect the iPhone Duo release to be one of the buggiest releases Apple has ever done.
Replies
7
Boosts
0
Views
423
Activity
12h
UISheetPresentationController issues on iPhone Duo
I have an App where I use the UISheetPresentationController to present a menu as a "drawer" (like the "FindMy" or "Maps") App. Because the sheet is presented over a map, I made the sheet semi-transparent/blurry, so the Map shines through, which looks nice. The sheet is using a UITableView with the "insetGroup" style, so the table cells have the nice rounded borders and there are margins to the sheet borders. When running the App on the iPhone Duo (Simulator) on the outer display, the tableView does no longer respect the "insetGroup" style, it is rendered like it would have the "plain" style, which destroys everything that look good. No rounded borders, no margins. However if I opt-out of the automatic "vertical toolbar behavior" (overriding preferredVerticalBarBehavior so it returns "disabled"), then everything looks great again, however then the sheet content might overlap with the sidebar icons and camera because it now covers the whole area up to the right screen border. Is this supposed to be this way (if yes, why?), is there a way to fix this, or do we have to wait for a bugfix within iOS 27.1? The tableview still claims to have the "insetGrouped" style, just it does not render this way. I did not see any similar issues under other circumstances. Only UISheetPresentationController seems to be affected by this. Is there a way to correctly detect if the App is running on an iPhone Duo, so we could use this detection to add workarounds for such issues?
Replies
4
Boosts
1
Views
517
Activity
17h
How to get UISheetPresentationController width to adjust for vertical toolbar on iPhone Duo?
If you run Safari in the iPhone Duo simulator and choose to share something you get a screen similar to the following: In my own app, if I present a UIActivityViewController I get a similar result. Note that the share sheet does not cover the vertical toolbar at all. So my question is how to present a UISheetPresentationController to look the same way. In other words, how to get the width of the UISheetPresentationController to take into account the vertical toolbar? All of my existing code to create and present a UISheetPresentationController result in the UISheetPresentationController taking the full width of the screen. The contents of the sheet take the safe area into account, but that's not the same result. I need the sheet itself to be narrower. I don't see an API for this. Or does this require more complicated presentation controller / delegate setup? Here is some relevant code in the view controller that I want displayed in the sheet: self.modalPresentationStyle = .popover self.presentationController?.delegate = self if let sheet = popoverPresentationController?.adaptiveSheetPresentationController { popoverPresentationController?.passthroughViews = [] sheet.detents = [ .medium(), .large() ] sheet.largestUndimmedDetentIdentifier = nil sheet.prefersGrabberVisible = false sheet.prefersScrollingExpandsWhenScrolledToEdge = true sheet.prefersEdgeAttachedInCompactHeight = true sheet.widthFollowsPreferredContentSizeWhenEdgeAttached = true } Or maybe UISheetPresentationController is the wrong approach.
Topic: UI Frameworks SubTopic: UIKit Tags:
Replies
0
Boosts
0
Views
70
Activity
23h
UIAlertController.addTextField results in broken text field in 27.1
I just downloaded Xcode 27.1 to test out the iPhone Duo simulator, and I notice that UIAlertController.addTextField, which was working fine in 27, is now very broken, resulting in a text field that is squashed vertically and pushed over to the right in the alert sheet. This is very easy to reproduce - the following code will show the problem if you build in Xcode 27.1 and run on iOS 27.1 or iOS 27.2: let alert = UIAlertController(title: "Create Something", message: "Enter a title.", preferredStyle: .alert) alert.addTextField { textField in textField.placeholder = "Title" } alert.addAction(UIAlertAction(title: "Cancel", style: .cancel)) present(alert, animated: true) The bug isn't limited to the Duo, but can also be seen on an iPad (and probably a regular phone). I would post a screenshot, but the last time I tried that, the forum software erroneously banned me for two weeks. I have reported this as bug #FB24889500, but given that we use alerts with text fields for users adding new items to the outline in our app, something the user does a lot, I'm wondering if there is a workaround, since this is going to make our app look very buggy.
Topic: UI Frameworks SubTopic: UIKit Tags:
Replies
1
Boosts
2
Views
290
Activity
1d
How to preserve collection view scroll anchor when folding/unfolding iPhone Duo
The following question was asked in the Oct 13 iPhone Duo group lab: when you unfold iPhone Duo after you’ve scrolled down, does UIKit keep the position or should we re-anchor ourselves? The answer was various scroll views like collection views and text views will handle this for you to keep visible items visible, which also works when resizing the window on iPad. This is not working for me with a simple UICollectionView. What do I need to do to obtain this behavior? class ViewController: UIViewController, UICollectionViewDataSource { override func viewDidLoad() { super.viewDidLoad() let layout = UICollectionViewFlowLayout() layout.itemSize = CGSize(width: 80, height: 80) layout.minimumInteritemSpacing = 8 layout.minimumLineSpacing = 8 layout.sectionInsetReference = .fromLayoutMargins let collectionView = UICollectionView(frame: .zero, collectionViewLayout: layout) collectionView.translatesAutoresizingMaskIntoConstraints = false collectionView.backgroundColor = .systemBackground collectionView.dataSource = self collectionView.insetsLayoutMarginsFromSafeArea = true collectionView.register(UICollectionViewCell.self, forCellWithReuseIdentifier: "Cell") view.addSubview(collectionView) NSLayoutConstraint.activate([ collectionView.topAnchor.constraint(equalTo: view.topAnchor), collectionView.leadingAnchor.constraint(equalTo: view.leadingAnchor), collectionView.trailingAnchor.constraint(equalTo: view.trailingAnchor), collectionView.bottomAnchor.constraint(equalTo: view.bottomAnchor) ]) } func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { 5000 } func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "Cell", for: indexPath) var content = UIListContentConfiguration.cell() content.text = String(indexPath.item) content.textProperties.alignment = .center cell.contentConfiguration = content var background = UIBackgroundConfiguration.clear() background.backgroundColor = .secondarySystemBackground cell.backgroundConfiguration = background return cell } } Run the app on iPhone Duo Scroll down to cell 100 on the outer display Unfold the device Expected: It should stay scrolled to item 100 Actual: It scrolled down to item 225 (or more accurately, the content offset did not change, more content was added higher up with the contentSize shrinking due to the expanded width) In the past I've put so much work into trying to maintain the expected scroll position for orientation changes on iPhone and iPad/Mac Catalyst resize events, it's surprisingly incredibly hard to get working in every scenario, so I am SUPER interested to learn the system can do it for us!
Replies
0
Boosts
0
Views
82
Activity
1d
How to set custom height for keyboard extension without resize flicker?
Description I'm developing a custom keyboard extension using UIInputViewController and need to set a specific height of 268 points. The keyboard functions correctly, but there's a visible flicker and resize animation during launch that I cannot eliminate. The Problem When the keyboard launches, iOS provides incorrect heights before settling on the correct one. At launch, the view starts at 0×0. Around 295ms later, iOS sets the frame to 440×956 which is full screen height and wrong. Around 373ms, iOS changes it to 440×452 which is still wrong. Finally around 390ms, iOS settles at 440×268 which matches our constraint. This causes visible flicker as the view resizes three times rapidly. The keyboard appears to shrink from full screen down to the correct height, and users can clearly see this animation happening. What I've Tried I've tried adding a height constraint on self.view which gives me the correct height but causes the visible flicker. I created a custom UIInputView subclass and overrode intrinsicContentSize to return my desired height. iOS completely ignores this and gives random heights like 471pt, 680pt, or 956pt instead. I set allowsSelfSizing to true on my UIInputView subclass. iOS ignores this property. I set preferredContentSize on the view controller. iOS ignores this as well. I tried adding the constraint in viewDidAppear instead of viewDidLoad, thinking iOS might have settled by then. It still causes flicker. I overrode the frame and bounds setters on my UIInputView to clamp the height to my desired value. iOS bypasses these overrides somehow. I overrode layoutSubviews to force the correct height after the super call. iOS still applies its own height. Specific Question What is the correct API or technique to specify a keyboard extension's height that iOS will respect immediately upon launch, without triggering the resize animation sequence? Other third-party keyboards like Grammarly and SwiftKey appear to have solved this problem. Their keyboards appear at the correct height without any visible flicker. How do they achieve this? Expected Outcome The keyboard should appear at 268pt height on the first frame with no visible resize animation. Steps to Reproduce Create a new iOS App project in Xcode and add a Keyboard Extension target. In KeyboardViewController.swift, add a height constraint in viewDidLoad: override func viewDidLoad() { super.viewDidLoad() let heightConstraint = view.heightAnchor.constraint(equalToConstant: 268) heightConstraint.priority = .defaultHigh heightConstraint.isActive = true let label = UILabel() label.text = "Demo Keyboard" label.textAlignment = .center label.translatesAutoresizingMaskIntoConstraints = false view.addSubview(label) NSLayoutConstraint.activate([ label.centerXAnchor.constraint(equalTo: view.centerXAnchor), label.centerYAnchor.constraint(equalTo: view.centerYAnchor) ]) } Build and run on a physical device. Enable the keyboard in Settings, then General, then Keyboard, then Keyboards. Open any app with a text field and switch to the custom keyboard using the globe button. Observe the height changing from around 956pt to 452pt to 268pt with visible animation. Environment iOS 17 and iOS 18 and 26.2, Xcode 16 and Xcode 26, affects all iPhone models tested, reproducible on both simulator and physical device.
Replies
4
Boosts
6
Views
1.1k
Activity
1d
iOS 27: print(to:) silently drops every job after the first
The problem On iOS 27, UIPrintInteractionController.print(to:completionHandler:) works on its first call in a process. Every subsequent call is accepted (print(to:) returns true and printInteractionControllerWillStartJob fires), but the completion handler is never invoked: nothing prints, didFinishJob never fires, no error is produced, and no job appears in Print Center. I expected each call to submit an independent job and invoke its completion handler, as it does on iOS 26 and earlier with the identical binary. Steps to reproduce Build an app that prints without the print panel, using a retained UIPrinter from UIPrinterPickerController. Submit a job: let controller = UIPrintInteractionController.shared let info = UIPrintInfo(dictionary: nil) info.outputType = .general info.jobName = "job-\(n)" controller.printInfo = info controller.printingItem = pdfData // valid PDF, canPrint(data) == true controller.delegate = self let started = controller.print(to: savedPrinter) { _, completed, error in print("completion", completed, String(describing: error)) } print("started", started) First job: started == true, both willStartJob and didFinishJob fire, the completion handler runs with completed == true, and the page prints. Submit a second job the same way, same process. started == true and willStartJob fires with printInfo.printerID populated and printPaper negotiated to the same values as the successful job. Then nothing. No didFinishJob, no completion handler, no error, no page, nothing in Print Center. A third job: print(to:) returns false synchronously, since the shared controller still considers job two in flight. System information iPad, iPadOS 27.0 developer beta 6 Built against iOS 26.2 SDK (Xcode 26.2). Same binary works on iOS 26. Reproduced on two unrelated printers: Brother QL-820NWB and Canon MF420 Series. Content is a small PDF (~11 to 13 KB); canPrintData: returns true. Troubleshooting tried Restarted the iPad and reinstalled the app. Each buys exactly one successful print before the failure returns. Compared observable state between the working and hung jobs. Identical in every respect. During a hang, printed the same content to the same printer from Files via the share sheet. Worked normally, including on repeat. Paused in the debugger during the hang. No blocked thread; no PrintKit frame, XPC wait, or semaphore anywhere in bt all. Called contactPrinter before each job on the retained printer. Returned true quickly, and the job still hung. Implemented printInteractionControllerParentViewController(_:) in case a presentation context was missing. UIKit never calls it on this path. Workaround Creating a new UIPrintInteractionController per job resolves it completely. A long-lived instance the app creates itself fails exactly like .shared does, so the issue is reuse of a controller that has already run a job, not the shared singleton specifically. Is per-job instantiation the supported pattern? The docs say the shared instance "represents a print job" but don't state whether a controller may be reused for a second job, and every sample I can find uses sharedPrintController with the present… methods rather than print(to:).
Replies
5
Boosts
7
Views
1.2k
Activity
1d
Layout margins guides are still broken the iPhone Duo (sim) and 27.1 RC
Layout margin guides are broken throughout UIKit and SwiftUI on the iPhone Duo sim in iOS 27.1 RC. For example, a cell which looks perfectly fine on a normal iPhone sim (which has a compact horizontal size class), has zero vertical layout margins on iPhone Duo. Here's some screenshots. The red dotted lines are supposed to show the margins in the cell content view, i.e., the boundary between default padding around the cell (for its background) and the content of the cell. On every other device and size class these all work, and will have some vertical margin. iPhone 18 Pro: iPhone Duo: As you can see, the border is cut off. No vertical margins at all. iPhone Duo Unfolded: Not only is it busted just in UICollectionViews. Check out this segmented control (also configured with layout margins). This works fine on catalyst, iPhone, and iPad. This makes me very nervous about shipping with the 27.1 SDK. Is this a known issue? If so, what is the recommended workaround in the meantime? FB25097501
Replies
5
Boosts
0
Views
293
Activity
1d
UISearchBar’s delegate method searchBarCancelButtonClicked is not called on search cancel when search bar is integrated into the navigation bar on iOS 27
Hi, I would like to share an issue with UISearchBar's delegate method searchBarCancelButtonClicked on iOS 27 beta. On iOS 27 beta, when search bar is integrated into navigation bar’s items, tapping search cancel button doesn’t invoke UISearchBar’s delegate method searchBarCancelButtonClicked:. Steps to reproduce: Create UINavigationController with one UIViewController Set up searchController. Set searchController.searchBar.delegate, preferredSearchBarPlacement = .integratedButton, searchBarPlacementAllowsToolbarIntegration = false Tap the search button and type a query Tap the search cancel button Expected: On iOS 26, the searchBarCancelButtonClicked delegate method is called. Actual: On iOS 27 beta, the searchBarCancelButtonClicked delegate method is NOT called. On iOS 27 beta, if search bar is “stacked” or placed in the toolbar rather than the navigation bar, the bug does not reproduce. I’m using Xcode Version 27.0 beta 6 with latest available iOS 27 iPhone 17 Pro simulator (24A5423a). I reported the issue via Feedback Assistant with a minimal reproduction example and 2 videos comparing the behavior between iOS 26 and iOS 27 beta. Here is the report ID: FB24636315. Here is the minimal reproduction example: // SceneDelegate.swift import UIKit class SceneDelegate: UIResponder, UIWindowSceneDelegate { var window: UIWindow? func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) { guard let windowScene = scene as? UIWindowScene else { return } let window = UIWindow(windowScene: windowScene) window.rootViewController = UINavigationController(rootViewController: ViewController()) window.makeKeyAndVisible() self.window = window } } // ViewController.swift import UIKit final class ViewController: UITableViewController { private let allItems = (1...30).map { "Item \($0)" } private var items: [String] = [] private var cancelCount = 0 override func viewDidLoad() { super.viewDidLoad() items = allItems updateTitle() let searchController = UISearchController(searchResultsController: nil) searchController.searchBar.delegate = self navigationItem.searchController = searchController navigationItem.preferredSearchBarPlacement = .integratedButton navigationItem.searchBarPlacementAllowsToolbarIntegration = false tableView.register(UITableViewCell.self, forCellReuseIdentifier: "cell") } private func updateTitle() { title = "Cancel presses: \(cancelCount)" } override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { items.count } override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) cell.contentConfiguration = { var config = cell.defaultContentConfiguration() config.text = items[indexPath.row] return config }() return cell } } extension ViewController: UISearchBarDelegate { func searchBarCancelButtonClicked(_ searchBar: UISearchBar) { print("searchBarCancelButtonClicked(_:)") cancelCount += 1 updateTitle() items = allItems tableView.reloadData() } } Thank you in advance!
Topic: UI Frameworks SubTopic: UIKit Tags:
Replies
2
Boosts
2
Views
365
Activity
1d
iOS App QuickType Bar Credit Card Autofill Not Working
According to this autofill credit card documentation we should be able to autofill credit card fields using the QuickType Bar for credit card fields, but it does not work. The QuickType Bar does not display for credit card fields (see screenshots) I have tested this on a physical device running iOS 27 (iPhone 16e), have added a card to the Autofill setting in the Wallet app, and have made sure my text fields have the correct textContentType values. I am able to autofill using the backup autofill menu, but it is less than ideal. It takes a minimum of 5 taps to autofill one field. It would be far less painful to just pull out the credit card and manually enter the information (see screenshot). Here is a link to my test project demonstrating the issue: https://drive.google.com/file/d/1wMGOUNhVnmt3rBAD0TSMf9NV39-JS9ij/view?usp=sharing
Replies
1
Boosts
0
Views
286
Activity
2d
iOS 26 beta3 Custom keyboard always displays a gray bar above it
Problem description: When using the Custom keyboard in various system application scenarios, a gray area is always displayed at the top of the Custom keyboard. Although the system has been restarted and the Custom keyboard has been restarted, and the pull-down operation has been repeated in multiple system application environments, the gray bar still appears. This problem also has the same problem on other input method software. Reproduction steps: Set the current input method to "CustomKeybaord" In the memo app or any other system app, pull up the Custom keyboard, or switch to the Custom keyboard. Observe whether a gray area is always displayed above the Custom keyboard. Request: I would like to understand whether the current behavior is a bug or if it requires Custom keyboards to adapt their style accordingly. However, I not found that currently unable to modify the style or color of the gray bar in question, and I do not have a suitable adaptation solution at this time. I would appreciate further assistance
Topic: UI Frameworks SubTopic: UIKit
Replies
6
Boosts
2
Views
644
Activity
2d
External Display stops working at iOS 27 / Xcode 27
I have an app that connects to an external display, the app controls content for the external display, but the external display is not active and uses the UIWindowSceneSessionRoleExternalDisplayNonInteractive role. I migrated the app to use UIScene lifecycle last year and everything seemed to be working. I use - (UISceneConfiguration *) application:(UIApplication *) application configurationForConnectingSceneSession:(UISceneSession *) connectingSceneSession options:(UISceneConnectionOptions *) options; in the AppDelegate to provide the configurations. But now at XCode 27/ iOS 27, that code is not called when I connect the external display with a dislpay adapter to my iPhone. But the device connects and shows a mirror of my iPhone display. What's going on?
Topic: UI Frameworks SubTopic: UIKit
Replies
2
Boosts
0
Views
86
Activity
2d
Save & Edit UIBarButtonSystemItems need to be updated for the iPhone Duo
When creating a UIBarButtonItem using the standard UIBarButtonSystemItem values of UIBarButtonSystemItemSave or UIBarButtonSystemEdit you end up with text-only buttons. The text-only buttons are an issue with the iPhone Duo since such buttons do not get put in the vertical sidebar. This is a problem with a view controller with scrollable content. The text-only Save or Edit buttons can scroll out of view leaving the user confused about how to complete their work on the screen. Related is the UIViewController editButtonItem which gives the standard Edit/Done toggle button. Since the button shows the text "Edit" the button doesn't get put in the vertical sidebar. This is despite the Done display being shown as a checkmark icon.
Topic: UI Frameworks SubTopic: UIKit Tags:
Replies
1
Boosts
0
Views
375
Activity
3d
Best practice Replacement for Edit Button on iPhone Duo
On the iPhone Duo the standard "Edit" button for navigation bars is a text-based button, and text-based buttons are not pushed to the vertical toolbars on the Duo. This looks sometimes silly, if it is the only remaining button that can not be placed in the vertical toolbar and which has the result that an almost empty horizontal navigation bar must be kept visible as well. So I guess it would be good idea to have an icon-based replacement for the Editor button to avoid having two toolbars on the Duo. Is there a best practice for the icon to pick for such an edit button? Would be "square.and.pencil" (SF Symbols) a good choice? Or better the "pencil .circle", because the "square" one is often used for text-based input? Anything better?
Replies
4
Boosts
0
Views
955
Activity
3d
UITableView row reordering no longer works under macOS 27 with Mac Catalyst
Under macOS 27 using Mac Catalyst for a UIKit-based app, If you present a view controller with a table view as a form sheet or page sheet, row reordering fails to function. You can drag a row as expected but the blue movement bar never appears and if you drop the row it simply returns to its original location. The exact same view controller presented as a popover works just fine. The exact same view controller not presented as a modal (such as the app's root controller) works just fine. This is a serious bug affecting existing applications and being reported by paying customers. This has been reported as FB25038883 which includes a simple sample app demonstrating the issue.
Replies
0
Boosts
0
Views
282
Activity
3d
UINavigationController, Nav Bar buttons incorrect layout on iPhone Duo
When presenting a UINavigationController presented via UIViewControllerRepresentable in a sheet, the top nav bar buttons aren't correctly moving to the side bar on the front screen of the Duo. They do re-orient vertically, but they do so next to the side bar and not within it. What am I doing wrong? This is how I am setting the buttons: let trimButton = UIBarButtonItem(image: UIImage(systemName: "selection.pin.in.out"), style: .plain, target: self, action: #selector(enterTrimming(_:))) navigationItem.leftBarButtonItem = trimButton navigationItem.rightBarButtonItem = cancelButton navigationItem.leftBarButtonItem?.isEnabled = true navigationItem.rightBarButtonItem?.isEnabled = true
Topic: UI Frameworks SubTopic: UIKit Tags:
Replies
1
Boosts
0
Views
101
Activity
3d
How to automatically size a table's footer view
Hi, I would like to automatically vertically size the table's footer view so that it has a fixed pre-defined minimum height and maximum height that fills up the gap between the last cell and the bottom of the safe area. How can I do this? PS: It seems to be that the footer view's size is not included in the table view's content size, correct? Regards, Hardy
Topic: UI Frameworks SubTopic: UIKit Tags:
Replies
1
Boosts
0
Views
59
Activity
3d
iPhone Duo: navigation bar item briefly moves to vertical bar during fullScreen dismissal despite .disabled
On the folded iPhone Duo display, a navigation bar item briefly moves into the vertical bar during dismissal of a full-screen modal, then jumps back to the top. Both navigation controllers consistently return .disabled from preferredVerticalBarBehavior, with childForPreferredVerticalBarBehavior returning nil. Environment Xcode 27.1 RC (27A9275), iOS 27.1 SDK, iPhone Duo simulator, folded outer display in portrait. Steps to reproduce Run the single-file UIKit example below in a scene-based app with a generated launch screen and no main storyboard. Tap the gear button on the Home screen to present Settings using .fullScreen. Tap the close button on Settings. Watch the Home screen's gear button during the dismissal animation. Expected The gear button stays in the top horizontal navigation bar throughout the transition, because the vertical bar preference is .disabled on both navigation controllers. Actual For part of the dismissal, the gear button appears below the status icons in the right-hand vertical bar region. It then jumps back to the top horizontal bar. The underlying tab bar also temporarily moves from the bottom to the right before returning. This reproduces with an otherwise empty view, standard UIKit containers, and the default bar appearance. No app code changes safeAreaInsets, bar frames, or animation timing. During the presentation/dismissal cycle, the Home view's logged right safe-area inset changes from 0 to 88 points and back to 0. In our app, content constrained to the safe area visibly narrows during the same transient change. In separate comparisons, returning .disabled from the root tab controller and content controllers, or requesting setNeedsUpdateOfVerticalBarConfiguration in appearance callbacks, did not eliminate the issue. Changing the modal to .overFullScreen avoided it in the tested simulator, but changes the underlying view controller lifecycle. The example below intentionally keeps .fullScreen to reproduce the problem. Is this expected behavior, or a known UIKit issue? Is there a supported way to keep .disabled effective throughout a fullScreen presentation/dismissal? Has this been addressed in a newer SDK/runtime? I have not tested iOS 27.2 or a physical Duo device. Minimal reproduction (one Swift file): import UIKit @main final class DemoAppDelegate: UIResponder, UIApplicationDelegate { func application(_ application: UIApplication, configurationForConnecting session: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration { let configuration = UISceneConfiguration(name: "Demo", sessionRole: session.role) configuration.delegateClass = DemoSceneDelegate.self return configuration } } final class DemoSceneDelegate: UIResponder, UIWindowSceneDelegate { var window: UIWindow? func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options: UIScene.ConnectionOptions) { guard let scene = scene as? UIWindowScene else { return } let home = DemoController() home.title = "首页" let navigation = DemoNavigationController(rootViewController: home) navigation.tabBarItem = UITabBarItem(title: "首页", image: UIImage(systemName: "house"), selectedImage: nil) let tabs = UITabBarController() if #available(iOS 18.0, *) { tabs.mode = .tabBar } tabs.viewControllers = [navigation] let window = UIWindow(windowScene: scene) window.rootViewController = tabs self.window = window window.makeKeyAndVisible() } } final class DemoNavigationController: UINavigationController { // 与音剪一致:导航容器固定横向栏,不转发给子页面。 @available(iOS 27.1, *) override var preferredVerticalBarBehavior: UIVerticalBarBehavior { .disabled } @available(iOS 27.1, *) override var childForPreferredVerticalBarBehavior: UIViewController? { nil } } final class DemoController: UIViewController { override func viewDidLoad() { super.viewDidLoad() view.backgroundColor = .systemBackground if title == "设置" { navigationItem.leftBarButtonItem = UIBarButtonItem(systemItem: .close, primaryAction: UIAction { [weak self] _ in self?.dismiss(animated: true) }) } else { navigationItem.rightBarButtonItem = UIBarButtonItem( image: UIImage(systemName: "gearshape"), primaryAction: UIAction { [weak self] _ in let settings = DemoController() settings.title = "设置" let navigation = DemoNavigationController(rootViewController: settings) navigation.modalPresentationStyle = .fullScreen self?.present(navigation, animated: true) }) } } override func viewDidLayoutSubviews() { super.viewDidLayoutSubviews() print("[DuoDemo] \(title ?? "") safe=\(view.safeAreaInsets) nav=\(navigationController?.navigationBar.frame ?? .zero) tab=\(tabBarController?.tabBar.frame ?? .zero)") } }
Replies
0
Boosts
0
Views
191
Activity
3d
UIScreen.screens.count differs on iPhone Duo sims depending on if app is IOS 26 SDK, or iOS 27 SDK
Hi there, My app uses UIScreen.screens.count (deprecated) to predict whether mirroring is happening on older iOS devices I noticed that the number of screens is different between iOS 26 SDK apps, and iOS 27 SDK apps. Can I expect that iOS 26 SDK apps will continue to return 1 screen like below for the iPhone Duo release?. I assume it's like this is to maximise compatibility. App built with SDK 26 on Xcode 27.1b1 iPhone Duo sim: UIScreen.screens.count == 1 App built with SDK 27 on Xcode 27.1b1 iPhone Duo sim: UIScreen.screens.count == 2 Thanks for the help! Sam
Topic: UI Frameworks SubTopic: UIKit Tags:
Replies
4
Boosts
0
Views
293
Activity
3d