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

Is it a bug in UIActivityViewController to Airdrop ?
Context: Xcode 26.3, iOS 18.7.6 on iPhone Xs In this iOS app, I call UIActivityViewController to let user Airdrop files from the app. When trying to send a URL whose file name contains some characters like accentuated (-, é, '), the transfer fails. Removing those characters makes it work without problem. The same app running on Mac (in iPad mode) works with both cases. I also noticed that even when airdrop fails, there is no error reported by activityVC.completionWithItemsHandler = { activity, success, items, error in } Are those known issues ?
Topic: UI Frameworks SubTopic: UIKit Tags:
4
0
198
16m
Layout glitch after rotation when using UIWindowScene sizeRestrictions on iPadOS 26
Hi everyone, I am experiencing a strange rendering issue on iPadOS 26 when sizeRestrictions.minimumSize is set on a UIWindowScene. After rotating the device and then rotating it back to the original orientation, the window appears to be stretched based on its previous dimensions. This resulting "stretched" area does not resize or redraw correctly, leaving a significant black region on the screen. Interestingly, as soon as I interact with the window (e.g., a slight drag or touch), the UI snaps back to its intended state and redraws perfectly. Here is a sample code and capture of behavior. 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 } windowScene.sizeRestrictions?.minimumSize = CGSize( width: 390, height: 844 // larger than the height of iPad in landscape ) // initialize... } } Has anyone else encountered this behavior? If so, are there any known workarounds to force a layout refresh or prevent this "ghost" black area during the rotation transition? Any insights would be greatly appreciated. Thanks!
0
0
39
5h
UIDocumentPickerViewController allows to select file declared in Info.plist document types even when restricting to folder UTI
My document-based UIKit app can open plain text files such as .txt files. When tapping a particular button I want to be able to select a folder, but when using the code below, the document picker allows me to select folders as well as .txt files: class DocumentViewController: UIDocumentViewController, UIDocumentPickerDelegate { override func viewDidAppear(_ animated: Bool) { let documentPicker = UIDocumentPickerViewController(forOpeningContentTypes: [.folder]) documentPicker.delegate = self present(documentPicker, animated: true) } } If I remove the text file entry from the Info.plist's document types list, it works as expected. Is this a bug and if yes, is there a workaround? <key>CFBundleDocumentTypes</key> <array> <dict> <key>CFBundleTypeName</key> <string>Text</string> <key>CFBundleTypeRole</key> <string>Editor</string> <key>LSHandlerRank</key> <string>Default</string> <key>LSItemContentTypes</key> <array> <string>public.text</string> </array> </dict> </array> I created FB22254960.
Topic: UI Frameworks SubTopic: UIKit Tags:
2
0
134
19h
Korean IME forces Smart Quotes, ignoring UITextInputTraits and OS Settings
There is a long-standing, structural issue with the iPadOS Korean IME when using a hardware keyboard. The IME forcibly intercepts the " (quote) keydown event and injects Unicode smart/curved quotes (“ or ”) directly into the text field. This hardcoded behavior ignores both: User Settings: The global "Smart Punctuation" toggle in [Settings > General > Keyboard] is completely ignored. Developer APIs: Setting UITextInputTraits.smartQuotesType = .no on a UITextView or UITextField has absolutely no effect when the Korean keyboard is active. Steps to Reproduce: Set smartQuotesType = .no on a standard UITextView. Connect a hardware keyboard. Switch input language to English -> Press the quote key. (Result: ASCII straight quote " - Correct behavior) Switch input language to Korean -> Press the quote key. (Result: Unicode curved quote “ - Incorrect behavior) Impact on Developers & Users: Because the OS IME forcefully injects the curved Unicode character before the app can process the raw key event, developers building code editors, markdown editors, or specific word processors (like Google Docs) cannot prevent this behavior. We cannot provide a standard text-editing experience for Korean users without forcing them to manually toggle their keyboard language to English just to type a straight quote. Expected Behavior: The Korean hardware keyboard IME must respect UITextInputTraits.smartQuotesType and the global OS toggle. Please provide a mechanism for developers and users to bypass this forced CJK typography rule.
1
0
51
1d
Korean IME forces Smart Quotes, ignoring UITextInputTraits and OS Settings
There is a long-standing, structural issue with the iPadOS Korean IME when using a hardware keyboard. The IME forcibly intercepts the " (quote) keydown event and injects Unicode smart/curved quotes (“ or ”) directly into the text field. This hardcoded behavior ignores both: User Settings: The global "Smart Punctuation" toggle in [Settings > General > Keyboard] is completely ignored. Developer APIs: Setting UITextInputTraits.smartQuotesType = .no on a UITextView or UITextField has absolutely no effect when the Korean keyboard is active. Steps to Reproduce: Set smartQuotesType = .no on a standard UITextView. Connect a hardware keyboard. Switch input language to English -> Press the quote key. (Result: ASCII straight quote " - Correct behavior) Switch input language to Korean -> Press the quote key. (Result: Unicode curved quote “ - Incorrect behavior) Impact on Developers & Users: Because the OS IME forcefully injects the curved Unicode character before the app can process the raw key event, developers building code editors, markdown editors, or specific word processors (like Google Docs) cannot prevent this behavior. We cannot provide a standard text-editing experience for Korean users without forcing them to manually toggle their keyboard language to English just to type a straight quote. Expected Behavior: The Korean hardware keyboard IME must respect UITextInputTraits.smartQuotesType and the global OS toggle. Please provide a mechanism for developers and users to bypass this forced CJK typography rule.
Topic: UI Frameworks SubTopic: UIKit
0
0
65
1d
Wrong appearance of decimalPad keyboard in dark mode
Hi. The following code causes UI mismatch on iOS26. Keyboard with type decimalPad and appearance as dark is displayed as popUp with wrong colors. Before iOS26 keyboard was regular with correct color scheme. Please advice either how to make the scheme correct or force to display regular keyboard instead of popup. class ViewController: UIViewController { @IBOutlet weak var textField: UITextField! override func viewDidLoad() { super.viewDidLoad() // Do any additional setup after loading the view. textField.keyboardType = .decimalPad textField.keyboardAppearance = .dark view.backgroundColor = .darkGray } }
6
1
301
5d
CarPlay: CPListImageRowItem images and CPNowPlayingTemplate buttons occasionally not displaying (requires device reboot)
Device: iPhone 17 Pro Max iOS version: iOS 26.3 CarPlay type: Wired We are encountering two intermittent UI issues in CarPlay when running our music application. The problems occur occasionally and cannot be recovered without restarting the device. Issue 1: CPListImageRowItem image not displaying On the CarPlay home page, some images occasionally fail to appear. Implementation details: The list is updated using CPListTemplate.updateSections. Each item is a CPListImageRowItem. On iOS versions below 26, images are updated using updateImages. On iOS 26, images are provided through CPListImageRowItem.elements, where each element is a CPListImageRowItemRowElement. Observed behavior: Logs confirm that the data is correctly provided. However, in failing cases the CPListImageRowItemRowElement appears with both title and subtitle equal to nil. The image is not rendered in the UI even though the item exists. Issue 2: Now Playing bottom buttons occasionally missing On the Now Playing screen, the bottom control buttons sometimes fail to appear. Implementation details: Buttons are updated using CPNowPlayingTemplate.updateNowPlayingButtons. The buttons are instances of CPNowPlayingImageButton. Observed behavior: Occasionally the buttons are not displayed. Once this occurs, the UI does not recover. Restarting the phone immediately resolves the issue. Additional observations The issue appears to occur intermittently. Once triggered, it persists until the device is rebooted. Similar behavior has been observed in other music apps (for example, QQ Music). Questions Are there known CarPlay UI rendering issues related to CPListImageRowItem or CPNowPlayingTemplate in recent iOS versions? Is there any recommended workaround or lifecycle handling that might prevent these UI elements from failing to render? Any guidance would be greatly appreciated.
Topic: UI Frameworks SubTopic: UIKit Tags:
1
0
44
6d
iOS 26: default gray background on UITabBarItem
In iOS 26, when a UITabBarItem is selected, a gray background appears behind the selected item. This seems to happen automatically with the new tab bar design. I tried configuring the tab bar using UITabBarAppearance, but the background highlight still appears. Is this the expected behavior in iOS 26 or is there a recommended way to configure the tab bar so that only the icon and title change color when selected?
Topic: UI Frameworks SubTopic: UIKit
4
0
245
1w
Switching to custom keyboard size glitches
I've created a custom keyboard and implemented the: class KeyboardViewController: UIInputViewController The imlementation looks like this: override func viewDidLoad() { super.viewDidLoad() var stack = UIStackView() stack.axis = .vertical stack.spacing = 8 stack.translatesAutoresizingMaskIntoConstraints = false stack.distribution = .fill stack.heightAnchor.constraint(equalToConstant: 200).isActive = true .... view.addSubview(stack) NSLayoutConstraint.activate([ stack.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 20), stack.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -20), stack.topAnchor.constraint(equalTo: view.topAnchor, constant: 10), stack.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: -10) ]) The problem is that the keyboard seems to start showing in the size (I've printed the parent frame): Optional(<UIView: 0x101008480; frame = (0 0; 390 844); autoresize = W+H; layer = <CALayer: 0x600000207b80>>) and than resizes to my given height. But it's not fast enough so that I can see some glitches whenever I switch from another keyboard to my custom keyboard. Is there a way to prevent this resizing or start the keyboard in a given size? This is just not the best user experience.
Topic: UI Frameworks SubTopic: UIKit
2
2
210
1w
Putting 2 existing pdf pages side by side (half size) in a new pdf
In Swift, iOS, I have a pdf file. I want to take the pages 2 by 2 and put them side by side, on the new page. For this, I have to scale initial pages half size and rotate .pi/2. I managed to achieve this by converting pdf pages to UIImages and using a UIGraphicsImageRenderer. But with a critical loss of resolution. I've tried improving the resolution by creating images as jpegData(withCompressionQuality: 1.0), to no avail. So I would need to work directly on the pdf pages using CGPDFDocument format. The code structure is as follows, to insert a single scaled page: for iPage in … { if let _page = theCGPdfDocument.page(at: 1) { var _pageRect: CGRect = _page.getBoxRect(CGPDFBox.mediaBox) writeContextInDestination!.beginPage(mediaBox: &_pageRect) // translate to compensate for the flip caused displacement writeContextInDestination!.translateBy(x: _pageRect.size.width, y: _pageRect.size.height) Scale (-1, -1) // rotate 180° // add rotate as needed writeContextInDestination!.scaleBy(x: -1, y: -1) writeContextInDestination!.clip(to: _pageRect) writeContextInDestination!.drawPDFPage(_page) writeContextInDestination!.endPage() // end the current page } } writeContextInDestination!.closePDF() But I do not succeed in inserting the drawing of the second page. I've tried repeating lines 7 to 11 for a second page at line 13. No success. What is the direction to look for ?
1
0
182
1w
touchesEnded: not triggered on newer iOS when view is inside UIScrollView (was working on iOS 18)
Hi everyone, I’m facing an issue with touch handling on newer iOS versions. I have a custom view controller implemented in Objective-C that overrides touchesEnded:. The same code works correctly on iOS 18, but on newer iOS versions (tested on iOS 26), touchesEnded: is no longer being triggered. Important observations: touchesBegan: is triggered. touchesEnded: is NOT triggered. touchesCancelled: is also NOT triggered. No code changes were made between iOS 18 and iOS 26. Same code, same sample works fine in iOS18 device but not in iOS26 device Questions: Has gesture arbitration behavior changed in recent iOS 26 versions when views are inside UIScrollView? Any clarification on whether this is intended behavior or a regression would be greatly appreciated. Thank you.
Topic: UI Frameworks SubTopic: UIKit
6
0
300
1w
PHAssetCreationRequest merges new Burst Photos into "Recently Deleted" instead of Library
Description I am observing a critical issue when saving burst photos using the Photos Framework. If a burst photo with the same burstIdentifier already exists in the "Recently Deleted" album, any new assets saved via PHAssetCreationRequest are automatically merged into that deleted entry instead of appearing in the main Library or "All Photos." Environment Framework: Photos Framework (iOS) API: [[PHPhotoLibrary sharedPhotoLibrary] performChanges:...] Code Snippet The following logic is used to save the burst assets: [[PHPhotoLibrary sharedPhotoLibrary] performChanges:^{ // 'paths' is a custom object providing the creation request PHAssetCreationRequest *assetCreationRqst = [paths assetCreationRqst]; assetCreationRqst.favorite = [FavorManager.shared isSetDownloadedAssetFavorite:self.curItem]; PHObjectPlaceholder *placeHolder = assetCreationRqst.placeholderForCreatedAsset; localIdentifier = placeHolder.localIdentifier; } completionHandler:^(BOOL success, NSError * _Nullable error) { if (success) { // The handler returns success, but the asset is invisible to the user [weakSelf handleDownloadSuccess:localIdentifier]; } // ... cleanup and completion ... }]; Steps to Reproduce Save a burst photo to the iPhone's built-in Photos app. Manually delete that burst photo so it moves to the "Recently Deleted" album. Execute the code above to save the same burst photo (or a new set containing the same burstIdentifier in its metadata). Check the main Photo Library / "All Photos" view. Observed Result The completionHandler returns success = YES, and a localIdentifier is generated. The photo does not appear in the main Library or "All Photos." The newly saved photo is silently merged into the existing burst set located inside the "Recently Deleted" folder. The user cannot see the new photo unless they manually "Restore" the deleted items from the album. Expected Behavior PHAssetCreationRequest should always result in a visible asset in the user's Library. Even if a matching burstIdentifier exists in "Recently Deleted," the system should treat the new request as a new independent asset or provide an error, rather than hiding it within a deleted collection.
5
0
361
1w
How to Reload Collection View (DiffableDataSource) after API Finishes Calling
Hello, I have a collection view that uses a diffable data source, and I am initiating an API call while configuring a cell RuntimeCell in the cell registration block inside setupDataSource(). The cell has a runtimeLabel property whose text I am setting inside a configureLabel(movieId:) function. I noticed that the collection view does not automatically refresh the text label once this API call finishes and after setting the text property on a UILabel in the collection view cell to a value retrieved during the API call. I presume this is because I need to call dataSource.apply(snapshot) myself to reload the changes in the collection view after the API call finishes retrieving the runtime data. However, since the API call happens via the configuration of the cell in the cell registration closure, this API call ends up being called infinitely if I call dataSource.apply(snapshot) every time the API call finishes (i.e. calling dataSource.applySnapshot() calls the closure for the cell registration handler which re-triggers the API call). What is the correct architecture to apply to accomplish reloading the collection view so that the text label appears once the API finishes calling? Thank you class MovieDetailViewController: UIViewController { func setupDataSource() { // ... let runTimeCellRegistration = UICollectionView.CellRegistration<RuntimeCell, Item> { cell, indexPath, item in cell.runtimeLabelDelegate = self cell.configureLabel(movieId: self.selectedMovie.id) } dataSource = UICollectionViewDiffableDataSource(collectionView: collectionView, cellProvider: { collectionView, indexPath, itemIdentifier in let section = Section(rawValue: indexPath.section) switch section { //... case .runtime: return collectionView.dequeueConfiguredReusableCell(using: runTimeCellRegistration, for: indexPath, item: itemIdentifier) //... } return nil }) } } protocol RuntimeLabelCellDelegate: AnyObject { func didUpdateRuntime() } class RuntimeCell: UICollectionViewCell { var runtimeLabel: UILabel! //... UI Setup func configureLabel(movieId: Int) { Task { do { let details = try await movieSearchService.fetchMovieDetails(movieId: movieId) await MainActor.run { let minutes = details.runTime let durationText = "\(minutes)m" var emojiText = "" if minutes < 90 { emojiText = "Short & Sweet ⚡️" } else if minutes > 150 { emojiText = "Get the snacks ready 🍿" } runtimeLabel.text = emojiText.isEmpty ? durationText : "\(durationText) • \(emojiText)" runtimeLabelDelegate?.didUpdateRuntime() } } catch { print("Failed to load details: \(error)") } } } } extension MovieDetailViewController: RuntimeLabelCellDelegate { func didUpdateRuntime() { var snapshot = dataSource.snapshot() snapshot.appendItems([.runtime], toSection: .runtime) dataSource.apply(snapshot, animatingDifferences: true) } }
Topic: UI Frameworks SubTopic: UIKit Tags:
0
0
80
2w
controller.textDocumentProxy.documentContext not detecting pasted text in Gmail or Email apps
I found an issue related to Gmail and Email apps. When I try to fetch text using controller.textDocumentProxy.documentContext, it works fine every time in my original app and in the Messages app. However, in Gmail or Email apps, after pasting text, controller.textDocumentProxy.documentContext returns nil until the pasted text is edited. The same scenario works correctly in Messages and my original app. i'm trying it from my keyboard extension and my keyboard builded bases on KeyboardKit SDK when i jump to text Document Proxy it's referring me to UITextDocumentProxy
Topic: UI Frameworks SubTopic: UIKit
1
0
301
2w
Invalid parameter not satisfying: parentEnvironment != nil
Since the beta releases of iPadOS 26 we have been having some crashes about Invalid parameter not satisfying: parentEnvironment != nil We got to contact a couple of users and we found out that the crash appears when entering a screen in a UINavigationController with the iPad device connected to a Magic Keyboard. If the device is not connected to the keyboard then nothing happens and everything works ok. From our end we haven't managed to reproduce the crash so I am pasting part of the stacktrace if it can be of any help. 3 UIKitCore 0x19dfd2e14 -[_UIFocusContainerGuideFallbackItemsContainer initWithParentEnvironment:childItems:] + 224 (_UIFocusContainerGuideFallbackItemsContainer.m:23) 4 UIKitCore 0x19dae3108 -[_UIFocusContainerGuideImpl _searchForFocusRegionsInContext:] + 368 (_UIFocusGuideImpl.m:246) 5 UIKitCore 0x19db28498 -[_UIFocusMapSnapshot addRegionsInContainer:] + 2720 (_UIFocusMapSnapshot.m:531) 6 UIKitCore 0x19db28900 -[_UIFocusMapSnapshot addRegionsInContainers:] + 160 (_UIFocusMapSnapshot.m:545) 7 UIKitCore 0x19d1313dc _UIFocusRegionSearchContextSearchForFocusRegionsInEnvironment + 632 (_UIFocusRegion.m:143) 8 UIKitCore 0x19db1d244 -[_UIFocusRegionContainerProxy _searchForFocusRegionsInContext:] + 140 (_UIFocusRegionContainerProxy.m:184) 9 UIKitCore 0x19db28498 -[_UIFocusMapSnapshot addRegionsInContainer:] + 2720 (_UIFocusMapSnapshot.m:531) 10 UIKitCore 0x19d1320fc _UIFocusItemContainerAddChildItemsInContextWithOptions + 596 (UIFocusItemContainer.m:183) 11 UIKitCore 0x19d131b98 _UIFocusRegionSearchContextAddChildItemsInEnvironmentContainer + 648 (_UIFocusRegion.m:108) 12 UIKitCore 0x19d131398 _UIFocusRegionSearchContextSearchForFocusRegionsInEnvironment + 564 (_UIFocusRegion.m:140) 13 UIKitCore 0x19db1d244 -[_UIFocusRegionContainerProxy _searchForFocusRegionsInContext:] + 140 (_UIFocusRegionContainerProxy.m:184) 14 UIKitCore 0x19db28498 -[_UIFocusMapSnapshot addRegionsInContainer:] + 2720 (_UIFocusMapSnapshot.m:531) 15 UIKitCore 0x19d1320fc _UIFocusItemContainerAddChildItemsInContextWithOptions + 596 (UIFocusItemContainer.m:183) 16 UIKitCore 0x19d131b98 _UIFocusRegionSearchContextAddChildItemsInEnvironmentContainer + 648 (_UIFocusRegion.m:108) 17 UIKitCore 0x19d131398 _UIFocusRegionSearchContextSearchForFocusRegionsInEnvironment + 564 (_UIFocusRegion.m:140) 18 UIKitCore 0x19db1d244 -[_UIFocusRegionContainerProxy _searchForFocusRegionsInContext:] + 140 (_UIFocusRegionContainerProxy.m:184) 19 UIKitCore 0x19db28498 -[_UIFocusMapSnapshot addRegionsInContainer:] + 2720 (_UIFocusMapSnapshot.m:531) 20 UIKitCore 0x19d1320fc _UIFocusItemContainerAddChildItemsInContextWithOptions + 596 (UIFocusItemContainer.m:183) 21 UIKitCore 0x19d131b98 _UIFocusRegionSearchContextAddChildItemsInEnvironmentContainer + 648 (_UIFocusRegion.m:108) 22 UIKitCore 0x19d131398 _UIFocusRegionSearchContextSearchForFocusRegionsInEnvironment + 564 (_UIFocusRegion.m:140) 23 UIKitCore 0x19db1d244 -[_UIFocusRegionContainerProxy _searchForFocusRegionsInContext:] + 140 (_UIFocusRegionContainerProxy.m:184) 24 UIKitCore 0x19db28498 -[_UIFocusMapSnapshot addRegionsInContainer:] + 2720 (_UIFocusMapSnapshot.m:531) 25 UIKitCore 0x19d1320fc _UIFocusItemContainerAddChildItemsInContextWithOptions + 596 (UIFocusItemContainer.m:183) 26 UIKitCore 0x19d131b98 _UIFocusRegionSearchContextAddChildItemsInEnvironmentContainer + 648 (_UIFocusRegion.m:108) 27 UIKitCore 0x19d131398 _UIFocusRegionSearchContextSearchForFocusRegionsInEnvironment + 564 (_UIFocusRegion.m:140) 28 UIKitCore 0x19db1d244 -[_UIFocusRegionContainerProxy _searchForFocusRegionsInContext:] + 140 (_UIFocusRegionContainerProxy.m:184) 29 UIKitCore 0x19db28498 -[_UIFocusMapSnapshot addRegionsInContainer:] + 2720 (_UIFocusMapSnapshot.m:531) 30 UIKitCore 0x19d1320fc _UIFocusItemContainerAddChildItemsInContextWithOptions + 596 (UIFocusItemContainer.m:183) 31 UIKitCore 0x19d131b98 _UIFocusRegionSearchContextAddChildItemsInEnvironmentContainer + 648 (_UIFocusRegion.m:108) 32 UIKitCore 0x19d131398 _UIFocusRegionSearchContextSearchForFocusRegionsInEnvironment + 564 (_UIFocusRegion.m:140) 33 UIKitCore 0x19db1d244 -[_UIFocusRegionContainerProxy _searchForFocusRegionsInContext:] + 140 (_UIFocusRegionContainerProxy.m:184) 34 UIKitCore 0x19db28498 -[_UIFocusMapSnapshot addRegionsInContainer:] + 2720 (_UIFocusMapSnapshot.m:531) 35 UIKitCore 0x19d1320fc _UIFocusItemContainerAddChildItemsInContextWithOptions + 596 (UIFocusItemContainer.m:183) 36 UIKitCore 0x19d131b98 _UIFocusRegionSearchContextAddChildItemsInEnvironmentContainer + 648 (_UIFocusRegion.m:108) 37 UIKitCore 0x19d131398 _UIFocusRegionSearchContextSearchForFocusRegionsInEnvironment + 564 (_UIFocusRegion.m:140) 38 UIKitCore 0x19db1d244 -[_UIFocusRegionContainerProxy _searchForFocusRegionsInContext:] + 140 (_UIFocusRegionContainerProxy.m:184) 39 UIKitCore 0x19db28498 -[_UIFocusMapSnapshot addRegionsInContainer:] + 2720 (_UIFocusMapSnapshot.m:531) 40 UIKitCore 0x19d132e08 -[_UIFocusMapSnapshot _capture] + 424 (_UIFocusMapSnapshot.m:403) 41 UIKitCore 0x19db2675c -[_UIFocusMapSnapshot _initWithSnapshotter:mapArea:searchArea:] + 476 (_UIFocusMapSnapshot.m:171) 42 UIKitCore 0x19d130dcc -[_UIFocusMapSnapshotter captureSnapshot] + 192 (_UIFocusMapSnapshotter.m:137) 43 UIKitCore 0x19db2045c -[_UIFocusMap _inferredDefaultFocusItemInEnvironment:] + 136 (_UIFocusMap.m:168) 44 UIKitCore 0x19daffd2c -[_UIFocusEnvironmentPreferenceEnumerationContext _inferPreferencesForEnvironment:] + 140 (_UIFocusEnvironmentPreferenceEnumerator.m:313) 45 UIKitCore 0x19d127ab4 -[_UIFocusEnvironmentPreferenceEnumerationContext _resolvePreferredFocusEnvironments] + 104 (_UIFocusEnvironmentPreferenceEnumerator.m:250) 46 UIKitCore 0x19d127394 -[_UIFocusEnvironmentPreferenceEnumerationContext preferredEnvironments] + 36 (_UIFocusEnvironmentPreferenceEnumerator.m:184) 47 UIKitCore 0x19d126e94 _enumeratePreferredFocusEnvironments + 400 (_UIFocusEnvironmentPreferenceEnumerator.m:503)
9
2
643
2w
UIScreen.isCaptured and sceneCaptureState report inactive while system screen recording continues when Live Activity is expanded
Hi, I’m trying to reliably detect when system screen recording finishes, and I’m observing behavior that I don’t fully understand when a Live Activity is expanded via Dynamic Island. Environment Devices: iPhone 16 Pro iOS: 26.2 Xcode: 26.2 Using UIScreen.isCaptured and UIWindowScene.sceneCaptureState Implementation: I observe capture state like this: private var observation: NSKeyValueObservation? func startObserving() { observation = UIScreen.main.observe(\.isCaptured, options: [.new]) { _, change in print("isCaptured:", change.newValue ?? false) } } I also check: window.traitCollection.sceneCaptureState Steps to Reproduce Start system screen recording from Control Center. Confirm UIScreen.main.isCaptured == true. Expand a Live Activity via the Dynamic Island (e.g. timer or call). Observe capture state values while the Live Activity UI is expanded. Observed Behavior While screen recording is still active: UIScreen.main.isCaptured becomes false sceneCaptureState becomes .inactive This state persists while the recording Live Activity is expanded The system recording indicator remains visible The device continues recording Expected Behavior (or Clarification Needed) My understanding was that UIScreen.isCaptured indicates whether the device screen is currently being captured (e.g. screen recording or mirroring). However, this behavior suggests that both isCaptured and sceneCaptureState reflect whether the current scene is part of the capture surface, rather than whether device-level recording is active. Is this the intended behavior when system-owned surfaces (such as expanded Live Activities) are promoted above the app’s scene? If so: Is there any supported way to reliably detect device-level screen recording state (as opposed to scene-level capture participation), in order to trigger logic when recording finishes? Thank you for any clarification.
Topic: UI Frameworks SubTopic: UIKit
0
0
65
2w
UIScrollView Layout issue
I run into a layout problem where I cannot center an image inside ScrollView which is also inside Navigation Controller. The problem is surely the fact that there is a navigation bar because using this view without NavigationContoller works fine and the image is centered but I don’t know how to account for the space that navigation bar takes up. Here is the code: import UIKit class PhotoViewController: UIViewController { var photoName: String private lazy var photoView = { let image = UIImageView() image.translatesAutoresizingMaskIntoConstraints = false image.contentMode = .scaleAspectFit image.clipsToBounds = true return image }() var photoViewBottomConstraint: NSLayoutConstraint? var photoViewLeadingConstraint: NSLayoutConstraint? var photoViewTopConstraint: NSLayoutConstraint? var photoViewTrailingConstraint: NSLayoutConstraint? private lazy var scrollView = { let sv = UIScrollView() sv.translatesAutoresizingMaskIntoConstraints = false return sv }() override func viewDidLoad() { super.viewDidLoad() setupUI() } override func viewWillLayoutSubviews() { super.viewWillLayoutSubviews() updateMinZoomScaleForSize(view.bounds.size) } func updateMinZoomScaleForSize(_ size: CGSize) { let widthScale = size.width / photoView.bounds.width let heightScale = size.height / photoView.bounds.height let minScale = min(widthScale, heightScale) scrollView.minimumZoomScale = minScale scrollView.zoomScale = minScale } func setupUI() { photoView.image = UIImage(named: photoName) scrollView.delegate = self view.addSubview(scrollView) scrollView.addSubview(photoView) setupConstraints() } func setupConstraints() { NSLayoutConstraint.activate([ scrollView.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor), scrollView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor), scrollView.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor), scrollView.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor) ]) photoViewLeadingConstraint = NSLayoutConstraint( item: photoView, attribute: .leading, relatedBy: .equal, toItem: scrollView, attribute: .leading, multiplier: 1, constant: 0 ) photoViewTopConstraint = NSLayoutConstraint( item: photoView, attribute: .top, relatedBy: .equal, toItem: scrollView, attribute: .top, multiplier: 1, constant: 0 ) photoViewTrailingConstraint = NSLayoutConstraint( item: photoView, attribute: .trailing, relatedBy: .equal, toItem: scrollView, attribute: .trailing, multiplier: 1, constant: 0 ) photoViewBottomConstraint = NSLayoutConstraint( item: photoView, attribute: .bottom, relatedBy: .equal, toItem: scrollView, attribute: .bottom, multiplier: 1, constant: 0 ) photoViewLeadingConstraint?.isActive = true photoViewTopConstraint?.isActive = true photoViewTrailingConstraint?.isActive = true photoViewBottomConstraint?.isActive = true } init(photoName: String) { self.photoName = photoName super.init(nibName: nil, bundle: nil) } required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } } extension PhotoViewController: UIScrollViewDelegate { func viewForZooming(in scrollView: UIScrollView) -> UIView? { photoView } func scrollViewDidZoom(_ scrollView: UIScrollView) { updateConstraintsForSize(view.bounds.size) } func updateConstraintsForSize(_ size: CGSize) { let yOffset = max(0, (size.height - photoView.frame.height) / 2) photoViewTopConstraint?.constant = yOffset photoViewBottomConstraint?.constant = yOffset let xOffset = max(0, (size.width - photoView.frame.width) / 2) photoViewLeadingConstraint?.constant = xOffset photoViewTrailingConstraint?.constant = xOffset view.layoutIfNeeded() } }
3
0
174
2w