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 ?
UIKit
RSS for tagConstruct and manage graphical, event-driven user interfaces for iOS or tvOS apps using UIKit.
Selecting any option will automatically load the page
Post
Replies
Boosts
Views
Activity
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
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
I have an iOS app that runs on Mac, in iPad mode.
In the menubar, some subitems are improperly labelled, featuring NSMENUITEMTITLEABOUT or NSMENUITEMHIDE or NSMENUITEMTITLE instead. Looks like it cannot find the name of the app.
I have tried to set display name to no avail.
Or is it a localisation issue ?
How to correct this ?
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.
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)
}
}
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
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)
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
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()
}
}
Platform
UIKit
iOS
UIActivityViewController
Environment
Device (issue reported): iPhone 16
iOS Version: 26.2
App Type: UIKit / Swift (standard modal presentation of UIActivityViewController)
Summary
When presenting UIActivityViewController to share a CSV file, the share sheet does not allow vertical scrolling, making lower actions (including Save to Files) unreachable.
The same flow works correctly when sharing a PDF, and the issue cannot be reproduced on other test devices.
Steps to Reproduce
Launch the app and log in
Navigate to More → Reports
Tap Export Report
Choose Export Report (CSV)
Observe the share sheet
Expected Result
The user should be able to vertically scroll the share sheet
All share actions (including Save to Files) should be reachable
Actual Result
Share sheet opens but vertical scrolling is disabled
Lower options (including Save to Files) are not reachable
No crash or console errors
Using the ContactUI framework CNContactViewController(forNewContact contact: CNContact?) to add a new contact to the ContactStore.
If the new contact does not have an attached image then the contact is saved correctly.
If the new contact DOES have an attached image then all entries in the phoneNumbers or emailAddresses array are doubled when written to the contactStore.
Viewing the contact via the Contacts app shows the duplications.
This is only happening on iOS26+. Earlier versions of the operating system do not show duplicates.
Has anyone else seen this issue?
Feedback reference: FB20910502
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
}
}
We are facing some weird issue in the UILabel initialisation. Also it is occurring sometimes.
class TextLabel: ConfigurableView<TextLabel.Config> {
struct Config {
var text: String = .empty
var font: UIFont?
var textColor: UIColor?
var maxLines: Int = 0
var attributedText: NSAttributedString?
var textAlignment: NSTextAlignment = .natural
var truncateWithMore: Bool = false
var onTapShowMore: (() -> Void)?
var onTap: (() -> Void)?
var accessibilityIdentifier: String?
}
private lazy var label: UILabel = {
let label = UILabel() **//##### Crash is occurring in this line.**
label.translatesAutoresizingMaskIntoConstraints = false
label.adjustsFontForContentSizeCategory = true
return label
}()
private lazy var tapGesture = UITapGestureRecognizer(target: self, action: #selector(onTap))
private var isTruncated = false
override func setUp() {
addSubview(label)
label.equalsContainer()
}
override func layoutSubviews() {
super.layoutSubviews()
updateContent()
}
override func setConfig(_ config: Config) {
super.setConfig(config)
updateContent()
}
@objc func onTap() {
if isTruncated {
config?.onTapShowMore?()
} else {
config?.onTap?()
}
}
func updateContent() {
guard let config = config else { return }
label.numberOfLines = config.maxLines
label.text = config.text
}
}
You can find my configurable view below.
import UIKit
class ConfigurableView<T>: UIControl {
private(set) var config: T?
init(_ config: T) {
super.init(frame: .zero)
setUp()
setConfig(config)
}
override init(frame: CGRect) {
super.init(frame: frame)
setUp()
}
required init(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func setUp() {
}
func setConfig(_ config: T) {
self.config = config
}
}
This crash is occurring randomly. Sometimes we could reproduce it in the app updates.
Topic:
UI Frameworks
SubTopic:
UIKit
If I delete Safari and only have another browser installed on my device, UIApplication.shared.open does not work. I think this is a bug. Why would it not work?
If Safari is not the main browser, UIApplication would open the URL in my main browser.
Those are valid use cases.
I would expect this API to work with any browser...
iOS 26.2
iPhone 14 Pro
guard let url = URL(string: "https://www.apple.com") else {
return
}
if UIApplication.shared.canOpenURL(url) {
UIApplication.shared.open(url)
} else {
print("Could not open URL")
}
Topic:
UI Frameworks
SubTopic:
UIKit
I'm using one UITabBarController which leads to 6 NavigationController. Therefore the user will get 4 icons displayed and one icon with three points to see the rest of the Navigation Controller.
If the user now tries to edit the list and moves one item from the hidden area towards the TabBar at the bottom, the App crashes with the error:
Exception
NSException * "Can't add self as subview" 0x0000600000d16040
I can see this effect at least on both my apps.
If the same compilation is run on a older iOS version, there is no crash.
Is there anything I have to take care of the configuration of the TabBar, when it comes to iOS26?
Topic:
UI Frameworks
SubTopic:
UIKit
iOS 26 – navigationItem.titleView shifted left when leftBarButtonItem is nil
Hi everyone,
I’m encountering a layout issue on iOS 26 related to navigationItem.titleView positioning.
What I’m Doing
I’m hiding the default back button and removing the left bar button item:
navigationItem.leftBarButtonItem = nil
navigationItem.hidesBackButton = true
navigationItem.setLeftBarButtonItems([], animated: true)
Then I create a custom titleView with a specific width calculated as:
Screen width minus the width of the two bar button items (left and right).
let titleView = UIView(frame: CGRect(origin: .zero, size: sizeOfTitleView))
let titleLabel = UILabel(frame: CGRect(origin: .zero, size: sizeOfTitleView))
Expected Behavior
On previous iOS versions, the titleView is perfectly centered in the navigation bar.
Actual Behavior (iOS 26)
On iOS 26, when leftBarButtonItem is nil, the titleView is pushed slightly to the left instead of being centered (see attached image).
Question
Has there been a change in UINavigationBar layout behavior in iOS 26?
What is the correct way to ensure the titleView remains perfectly centered when there is no leftBarButtonItem?
Any guidance would be appreciated. Thanks!
hello, I have been receiving crash reports on iPadOS 26.1, When UITrackingElementWindowController viewDidDisappear
The feedback associated with this post is: FB20986398 and Exception
Exception
'Cannot remove an observer <PKTextEffectsWindowObserver 0x10854cbe0> for the key path "frame" from <UITextEffectsWindow 0x10827ca00> because it is not registered as an observer.'
#1 0x0000000183529814 in objc_exception_throw ()
#2 0x00000001845065a4 in -[NSObject(NSKeyValueObserverRegistration) _removeObserver:forProperty:] ()
#3 0x00000001845069c8 in -[NSObject(NSKeyValueObserverRegistration) removeObserver:forKeyPath:] ()
#4 0x00000001845068e0 in -[NSObject(NSKeyValueObserverRegistration) removeObserver:forKeyPath:context:] ()
#5 0x00000001cb22e894 in -[PKTextEffectsWindowObserver dealloc] ()
#6 0x000000018beafb28 in _setInteractionView ()
#7 0x000000018d81e8b8 in -[UIView(Dragging) removeInteraction:] ()
#8 0x00000001cb216448 in -[PKTextInputInteraction willMoveToView:] ()
#9 0x000000018beafb1c in _setInteractionView ()
#10 0x000000018d81e8b8 in -[UIView(Dragging) removeInteraction:] ()
#11 0x000000018d5ab094 in -[UIEditingOverlayViewController _removeInteractions] ()
#12 0x000000018cb166a8 in -[UIViewController _setViewAppearState:isAnimating:] ()
#13 0x000000018cb16d70 in __52-[UIViewController _setViewAppearState:isAnimating:]_block_invoke_2 ()
#14 0x000000018cb16c10 in __52-[UIViewController _setViewAppearState:isAnimating:]_block_invoke ()
#15 0x000000018655ef78 in __NSARRAY_IS_CALLING_OUT_TO_A_BLOCK__ ()
#16 0x00000001866b4a24 in -[__NSArrayI enumerateObjectsWithOptions:usingBlock:] ()
#17 0x000000018cb16a44 in -[UIViewController _setViewAppearState:isAnimating:] ()
#18 0x000000018cb1753c in -[UIViewController __viewDidDisappear:] ()
#19 0x000000018cb17638 in -[UIViewController _endAppearanceTransition:] ()
#20 0x000000018ca2401c in __48-[UIPresentationController transitionDidFinish:]_block_invoke ()
#21 0x000000018ca23cd0 in -[UIPresentationController transitionDidFinish:] ()
#22 0x000000018ca2d720 in -[_UICurrentContextPresentationController transitionDidFinish:] ()
#23 0x000000018ca27608 in __77-[UIPresentationController runTransitionForCurrentStateAnimated:handoffData:]_block_invoke.106 ()
#24 0x000000018cb31fec in -[_UIViewControllerTransitionContext completeTransition:] ()
#25 0x000000018d7f09bc in -[UITransitionView notifyDidCompleteTransition:] ()
#26 0x000000018d7f0750 in -[UITransitionView _didCompleteTransition:] ()
#27 0x000000018bf1c2a4 in __UIVIEW_IS_EXECUTING_ANIMATION_COMPLETION_BLOCK__ ()
#28 0x000000018d817960 in -[UIViewAnimationBlockDelegate _didEndBlockAnimation:finished:context:] ()
#29 0x000000018d7f7168 in -[UIViewAnimationState sendDelegateAnimationDidStop:finished:] ()
#30 0x000000018d7f75cc in -[UIViewAnimationState animationDidStop:finished:] ()
#31 0x000000018d7f763c in -[UIViewAnimationState animationDidStop:finished:] ()
#32 0x0000000186fedda4 in run_animation_callbacks ()
#33 0x000000010365e2d0 in _dispatch_client_callout ()
#34 0x000000010367f4c0 in _dispatch_main_queue_drain.cold.5 ()
#35 0x0000000103654778 in _dispatch_main_queue_drain ()
#36 0x00000001036546b4 in _dispatch_main_queue_callback_4CF ()
#37 0x00000001865b42c8 in __CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__ ()
#38 0x0000000186567b3c in __CFRunLoopRun ()
#39 0x0000000186566a6c in _CFRunLoopRunSpecificWithOptions ()
#40 0x0000000226ee5498 in GSEventRunModal ()
#41 0x000000018bf2aba4 in -[UIApplication _run] ()
#42 0x000000018bed3a78 in UIApplicationMain ()
What works
let backButton = UIBarButtonItem(title: "", style: .plain, target: nil, action: nil)
backButton.hidesSharedBackground = true
self.navigationItem.rightBarButtonItem = backButton
// or
self.navigationItem.leftBarButtonItem = backButton
What doesn't work
let backButton = UIBarButtonItem(title: "", style: .plain, target: nil, action: nil)
backButton.hidesSharedBackground = true
self.navigationItem.backBarButtonItem = backButton
I've tried setting this property on all possible permutations and combinations e.g. Inside navigationController(_ navigationController: UINavigationController, willShow viewController: UIViewController, animated: Bool) and pushViewController(_ viewController: UIViewController, animated: Bool) of a custom UINavigationController to make sure.
Expected vs Actual behavior
Setting hidesSharedBackground = true should remove the glass background from both regular bar button items and back bar button items but it has no effect on backBarButtonItem.
Additional context
I’m aware of the UIDesignRequiresCompatibility Info.plist key, but I’m looking for a programmatic solution if there is one. The goal is to remove the glass background from back buttons.
Hi,
I have two views in my view hierarchy searchButtonView and searchBarView. I am trying to fade out the searchButtonView while animating the change in the frame of searchBarView simultaneously within a UIView.animate block. However, when I run the app, the frame of searchBarView resizes correctly while the alpha of searchButtonView does not animate to 0 as expected.
How can I fix this so that both view animate simultaneously?
Please see my code below.
Thank you
class MovieTitlesViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
var searchButtonView: UIView!
var searchBarView: UIView!
override func viewDidLayoutSubviews() {
createSearchButtonView()
createSearchBarView()
}
func createSearchButtonView() {
searchButtonView = UIView(frame: CGRect(x: 23, y: view.safeAreaInsets.top, width: 48, height: 48))
let searchImageView = UIImageView(image: UIImage(named: "Search Icon")!)
searchImageView.frame = CGRect(x: searchButtonView.frame.width / 2 - 16,
y: searchButtonView.frame.height / 2 - 16,
width: 32,
height: 32)
searchButtonView.addSubview(searchImageView)
searchButtonView.backgroundColor = .blue
searchButtonView.layer.cornerRadius = 24
searchButtonView.layer.borderColor = UIColor.gray.cgColor
searchButtonView.layer.borderWidth = 0.5
let tapGesture = UITapGestureRecognizer(target: self, action: #selector(tappedSearchView))
tapGesture.numberOfTapsRequired = 1
searchButtonView.addGestureRecognizer(tapGesture)
searchButtonView.isUserInteractionEnabled = true
view.addSubview(searchButtonView)
}
func createSearchBarView() {
searchBarView = UIView(frame: CGRect(x: 23,
y: view.safeAreaInsets.top,
width: 0,
height: 48))
searchBarView.backgroundColor = .red
// searchBarView.backgroundColor = UIColor(red: 217/255, green: 217/255, blue: 217/255, alpha: 1.0)
searchBarView.layer.cornerRadius = 24
searchBarView.layer.borderColor = UIColor.gray.cgColor
searchBarView.layer.borderWidth = 0.5
view.addSubview(searchBarView)
}
func animateExpandSearchView() {
UIView.animate(withDuration: 0.25, delay: 0.0, options: .curveEaseInOut) {
self.searchButtonView.alpha = 0.0
self.searchBarView.frame = CGRect(x: 23, y: self.view.safeAreaInsets.top, width: UIScreen.main.bounds.width - 46, height: 48)
}
}
@objc func tappedSearchView() {
print("tapped search view")
animateExpandSearchView()
}
}
Topic:
UI Frameworks
SubTopic:
UIKit