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

'editButtonItem.title' Cannot Be Updated in iOS 26
In iOS 26, I found that editButtonItem.title cannot be programmatically updated as before. Even when explicitly setting the title in viewWillAppear or inside setEditing(_:animated:), the text remains the default “Edit” / “☑️”. Here is a minimal reproducible example: import UIKit class ViewController: UIViewController { private let infoLabel: UILabel = { let l = UILabel() l.text = "uneditable" l.font = .systemFont(ofSize: 28, weight: .medium) l.textAlignment = .center l.translatesAutoresizingMaskIntoConstraints = false return l }() private let textField: UITextField = { let tf = UITextField() tf.placeholder = "This will become effective when you edit it." tf.borderStyle = .roundedRect tf.translatesAutoresizingMaskIntoConstraints = false tf.isEnabled = false return tf }() override func viewDidLoad() { super.viewDidLoad() view.backgroundColor = .systemBackground navigationItem.title = "sample" navigationItem.rightBarButtonItem = editButtonItem setupLayout() } override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) updateEditButtonTitle() } private func setupLayout() { view.addSubview(infoLabel) view.addSubview(textField) NSLayoutConstraint.activate([ infoLabel.centerXAnchor.constraint(equalTo: view.centerXAnchor), infoLabel.centerYAnchor.constraint(equalTo: view.centerYAnchor, constant: -40), textField.topAnchor.constraint(equalTo: infoLabel.bottomAnchor, constant: 20), textField.leadingAnchor.constraint(equalTo: view.layoutMarginsGuide.leadingAnchor), textField.trailingAnchor.constraint(equalTo: view.layoutMarginsGuide.trailingAnchor), textField.heightAnchor.constraint(equalToConstant: 44), ]) } override func setEditing(_ editing: Bool, animated: Bool) { super.setEditing(editing, animated: animated) textField.isEnabled = editing infoLabel.text = editing ? "editable" : "uneditable" if editing { textField.becomeFirstResponder() } else { textField.resignFirstResponder() } updateEditButtonTitle() } private func updateEditButtonTitle() { editButtonItem.title = isEditing ? "done" : "edit" } } Expected behavior Changing editButtonItem.title should update the displayed title of the bar button item. Actual behavior (iOS 26) The title remains the default “Edit” / “☑️” text, ignoring programmatic updates. This worked in previous iOS versions. It appears that in iOS 26 the system may be overriding editButtonItem.title automatically, preventing custom titles. Is this an intentional change, or a bug introduced in iOS 26?
Topic: UI Frameworks SubTopic: UIKit
1
0
60
4w
WKWebView touch event listener misdirect in iOS 18.5
Hello, after the IOS update 18.5, all elements with an touch-event listener inside a wkWebview seem to offset a touch-events origin x and y location by a factor of 0.666. Triggering any other element with an touch-event listener at that location instead. If there is not on an element with an touch-event listener at the offset location, nothing happens. Only if the offset origin is coincidentally still inside the actually touched element, the touch-event gets dispatched correctly. This effects only the event listener: "touchstart", "touchmove" and "touchend". click-event listeners still work, and trigger on the correct element. Confusing are the contents of the touch-events being dispatched. The attributes "pageX" and "pageY" report the correct position touched, yet "target" gives the (wrong) Element at the offset location. The offset location can be found in "targetTouches[0].pageX" and "targetTouches[0].pageY". The offset factor can be influenced by the "width" value of this header tag: "". If the width value is 240 the factor changes to 1.333, and the value 320 actually fixes this offset completely. Device: Iphone XS with IOS 18.5 <html> <head> <meta content="text/html; charset=UTF-8" http-equiv="content-type"/> <!--<meta name="viewport" content="width=240, user-scalable=no"/>--> <meta name="apple-mobile-web-app-capable" content="yes"/> <meta name="apple-mobile-web-app-status-bar-style" content="black"/> <meta name="format-detection" content="telephone=no"/> <link rel="apple-touch-icon" href="applogo"/> </head> <body> <style> div{ height:70px; width: 100%; margin-top: 7px; background-color: #f7f7f7; } </style> <div id="Feedback" style="background-color:white;font-size:10px;"></div> <div id="A" ontouchstart="insertTouchFeedback">Element A</div> <div id="B">Element B</div> <div id="C">Element C</div> <div id="D">Element D</div> <div id="E">Element E</div> <div id="F">Element F</div> <div id="G">Element G</div> <script> const feedback = document.getElementById("Feedback"); function insertTouchFeedback(event){ const offsetX = event.pageX - event.targetTouches[0].pageX; const offsetY = event.pageY - event.targetTouches[0].pageY; feedback.innerHTML = ` Hit on ${event.pageX}x${event.pageY} <br/> Actually triggers "${event.target.innerHTML}" at ${event.targetTouches[0].pageX}x${event.targetTouches[0].pageY} <br/> Offset ${offsetX}x${offsetY} <br/> Factor ${event.targetTouches[0].pageX / event.pageX} x ${event.targetTouches[0].pageY / event.pageY} `; } document.getElementById("A").addEventListener("touchstart", insertTouchFeedback); document.getElementById("B").addEventListener("touchstart", insertTouchFeedback); document.getElementById("C").addEventListener("touchstart", insertTouchFeedback); document.getElementById("D").addEventListener("touchstart", insertTouchFeedback); document.getElementById("E").addEventListener("touchstart", insertTouchFeedback); document.getElementById("F").addEventListener("touchstart", insertTouchFeedback); document.getElementById("G").addEventListener("touchstart", insertTouchFeedback); </script> </body> </html> We use WKWebView within Objective-C. Any idea whet goes wrong would be great! Thanks!
Topic: UI Frameworks SubTopic: UIKit
3
0
94
4w
CPNavigationAlert image size very small with long title variant
I am using CPNavigationAlert and am getting a specific name for the title, so I do not have more than one variant. Sometimes, the variant title is longer, which for some reason makes the image very small. I have tried to make sure to keep displayScale in mind: let maximumImageSize = CPListItem.maximumImageSize let displayScale = self.interfaceController?.carTraitCollection.displayScale ?? 2 let imageSize = CGSizeMake(maximumImageSize.width * displayScale, maximumImageSize.width * displayScale) let image = CarPlayMapUtility().getIconAlertImage(item: item, frame: imageSize) If the titleVariants is shorter, the image is displayed corrected. If it is longer, the image might be extremely small or not shown at all. Is this expected?
Topic: UI Frameworks SubTopic: UIKit Tags:
1
0
53
4w
UISearchController cannot become first responder when switching to a search tab
I would like my users to be able to switch to the search tab (in the sidebar) on iPad and immediately start typing. This is not possible. Calling becomeFirstResponder in viewDidLoad and viewWillAppear does not work. Only in viewDidAppear it does, but that comes with a significant delay between switching to the tab and the search field becoming active. Is there something else I can do? FB19588765 let homeTab = UITab( title: "Home", image: UIImage(systemName: "house"), identifier: "Home" ) { _ in UINavigationController(rootViewController: ViewController()) } let searchTab = UISearchTab { _ in UINavigationController(rootViewController: SearchViewController()) } let tabBarController = UITabBarController(tabs: [ homeTab, searchTab ]) tabBarController.mode = .tabSidebar class SearchViewController: UIViewController { let searchController = UISearchController(searchResultsController: nil) override func viewDidLoad() { super.viewDidLoad() self.view.backgroundColor = .systemBackground self.title = "Search" self.navigationItem.searchController = searchController self.navigationItem.preferredSearchBarPlacement = .integratedCentered searchController.becomeFirstResponder() // Does not work. searchController.searchBar.becomeFirstResponder() // Does not work. } override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) searchController.searchBar.becomeFirstResponder() // Does not work. } override func viewDidAppear(_ animated: Bool) { super.viewDidAppear(animated) searchController.searchBar.becomeFirstResponder() // Works. But comes with a significant delay. } }
Topic: UI Frameworks SubTopic: UIKit Tags:
2
0
65
4w
UISegmentedControl Not Switching Segments on iOS Beta 26
While testing my application on iOS beta 26, I am experiencing issues with the native UISegmentedControl component from UIKit. After implementing the control, I noticed that I am unable to switch to the second segment option—the selection remains fixed on the first segment regardless of user interaction. I have already reviewed the initial configuration of the control, the addition of the segments, and the implementation of the target-action, but the issue persists. I would like to understand what could be causing this behavior and if there are any specific adjustments or workarounds for iOS 26. I created a minimal application containing only a UISegmentedControl to clearly demonstrate the issue.
18
4
548
4w
iOS 26 beta6 UIEditMenuListView crash
*** Terminating app due to uncaught exception 'CALayerInvalidGeometry', reason: 'CALayer position contains NaN: [nan 106.333]. Layer: <CALayer:0x15c3f2d60; position = CGPoint (0 0); bounds = CGRect (0 0; 0 57.6667); delegate = <_UIEditMenuListView: 0x162400780; frame = (0 0; 0 57.6667); anchorPoint = (30, 0); alpha = 0; layer = <CALayer: 0x15c3f2d60>>; sublayers = (<CALayer: 0x1625005a0>, <CALayer: 0x15c3f2130>); opaque = YES; allowsGroupOpacity = YES; anchorPoint = CGPoint (30 0); opacity = 0>'
Topic: UI Frameworks SubTopic: UIKit
1
2
259
4w
iOS 26 UISplitViewController in dark mode appearance.
We have encountered a problem on iOS 26. When switching to dark mode, the color of all subviews (font color, background color, etc.) of the Sidebar (Primary View) of UISplitViewController will not change. For example, if it is set to the color of UIColor.label, it will always be black and will not be white in dark mode. On Xcode, just create a UISplitViewController in Storyboard without changing any settings, and run it directly to see the following: The title of the Navigation Bar defaults to the label color, and it is still black after switching to dark mode. There is no such problem in the Secondary View or other places. This problem has occurred since iOS 26 beta 3, and iOS 26 beta 4 is now the same. But beta 1 and beta 2 have no problem. I'm not sure if this is a bug, or if there is something that needs to be changed to adapt to iOS 26?
Topic: UI Frameworks SubTopic: UIKit Tags:
7
4
514
4w
Unable to Tint Custom View in UIBarButtonItem on iOS 26
When using a custom UIButton as the customView for a UIBarButtonItem in iOS 26, setting the tintColor on the UIBarButtonItem or the button itself does not affect the button’s appearance in the navigation bar. The button displays, but the tint is not applied as expected. Steps to Reproduce: Create a new iOS project with a navigation controller. Use the following code in your view controller: class ViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() view.backgroundColor = .secondarySystemBackground var configuration = UIButton.Configuration.plain() configuration.title = "Why Not Tinted...?" configuration.baseForegroundColor = .systemBlue configuration.contentInsets = NSDirectionalEdgeInsets(top: 12, leading: 12, bottom: 12, trailing: 12) let button = UIButton(configuration: configuration) let rightBarButton = UIBarButtonItem(customView: button) rightBarButton.tintColor = .green navigationItem.rightBarButtonItem = rightBarButton } } Expected Result: The UIButton in the navigation bar should appear green with glass effect, according to the tintColor set on the UIBarButtonItem. Actual Result: The UIButton appears, but the tintColor is not applied. Changing the tintColor on either the UIBarButtonItem or the UIButton has no effect on its appearance in the navigation bar.
Topic: UI Frameworks SubTopic: UIKit Tags:
2
0
101
4w
UISearchController scope buttons disappear forever after dismissing search when embedded in a search tab
When a UISearchController is placed inside a search tab, the scope buttons disappear when dismissing the search bar once. They never return. When using in any regular view controller container, like even another default tab, everything works fine. Is there something I can do to prevent this? Video: https://mastodon.social/@nicoreese/115017696077771370 FB19587916 let homeTab = UITab( title: "Home", image: UIImage(systemName: "house"), identifier: "Home" ) { _ in UINavigationController(rootViewController: ViewController()) } let searchTab = UISearchTab { _ in UINavigationController(rootViewController: SearchViewController()) } let tabBarController = UITabBarController(tabs: [ homeTab, searchTab ]) tabBarController.mode = .tabSidebar class SearchViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() self.view.backgroundColor = .systemBackground self.title = "Home" let searchController = UISearchController(searchResultsController: nil) searchController.searchBar.scopeButtonTitles = [ "Scope 1", "Scope 2" ] searchController.searchBar.showsScopeBar = true self.navigationItem.searchController = searchController } }
Topic: UI Frameworks SubTopic: UIKit Tags:
1
1
75
4w
Leading Swipe action in UIPageViewController is not working when it is pushed on UINavigationController.
When a UIPageViewController is pushed in a UINavigationController, the leading swipe action from middle of screen dismisses the PageViewController instead of going to previous page. When the Example code is opened from Xcode 16.4.0, ✅ Left Swipe action from left screen edge of screen dismisses the Page View Controller. ✅ Left Swipe action from middle of screen goes to previous Page in Page View Controller When the Example code is opened from Xcode 26.0 - Beta 6, ✅ Left Swipe action from left screen edge of screen dismisses the Page View Controller. ❌ Left Swipe action from middle of screen sometimes goes to previous page and sometimes dismisses the Page View Controller. Example code that the issue occurs: import Foundation import UIKit import PlaygroundSupport PlaygroundPage.current.setLiveView( UINavigationController(rootViewController: RootViewController()) ) class RootViewController: UIViewController { lazy var pageVCButton: UIButton = { let button = UIButton() button.setTitle("Open Page VC", for: .normal) button.setTitleColor(.label, for: .normal) button.addAction(UIAction(handler: { [weak self] _ in self?.didTapPageVCButton() }), for: .touchUpInside) return button }() lazy var pageContainerViewController = PageContainerViewController(startIndex: 3) func didTapPageVCButton() { print("didTapPageVCButton") navigationController?.pushViewController(pageContainerViewController, animated: true) } override func viewDidLoad() { super.viewDidLoad() view.backgroundColor = .systemBackground addOpenPageVCButton() } private func addOpenPageVCButton() { view.addSubview(pageVCButton) pageVCButton.translatesAutoresizingMaskIntoConstraints = false NSLayoutConstraint.activate([ pageVCButton.centerXAnchor.constraint(equalTo: view.centerXAnchor), pageVCButton.centerYAnchor.constraint(equalTo: view.centerYAnchor), ]) } } class PageContainerViewController: UIViewController { lazy var pageViewController: UIPageViewController = { let pageViewController = UIPageViewController( transitionStyle: .scroll, navigationOrientation: .horizontal, options: nil ) pageViewController.dataSource = self pageViewController.delegate = self return pageViewController }() lazy var pages: [ColouredViewController] = [ ColouredViewController(backgroundColor: .red), ColouredViewController(backgroundColor: .blue), ColouredViewController(backgroundColor: .green), ColouredViewController(backgroundColor: .yellow), ColouredViewController(backgroundColor: .brown), ColouredViewController(backgroundColor: .link), ColouredViewController(backgroundColor: .cyan), ] var startIndex = 0 init(startIndex: Int) { super.init(nibName: nil, bundle: nil) self.startIndex = startIndex } required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } override func viewDidLoad() { super.viewDidLoad() navigationController?.title = "Page View Controller" print(pageViewController.gestureRecognizers) setupPageViewController() } override func viewDidAppear(_ animated: Bool) { super.viewDidAppear(animated) } private func setupPageViewController() { addChild(pageViewController) view.addSubview(pageViewController.view) pageViewController.didMove(toParent: self) pageViewController.view.translatesAutoresizingMaskIntoConstraints = false NSLayoutConstraint.activate([ pageViewController.view.topAnchor.constraint(equalTo: view.topAnchor), pageViewController.view.bottomAnchor.constraint(equalTo: view.bottomAnchor), pageViewController.view.leadingAnchor.constraint(equalTo: view.leadingAnchor), pageViewController.view.trailingAnchor.constraint(equalTo: view.trailingAnchor), ]) pageViewController.setViewControllers([pages[startIndex]], direction: .forward, animated: true) } } extension PageContainerViewController: UIPageViewControllerDataSource { func pageViewController(_ pageViewController: UIPageViewController, viewControllerBefore viewController: UIViewController) -> UIViewController? { print("Leading Swipe") guard let viewController = viewController as? ColouredViewController else { return nil } guard let currentPageIndex = pages.firstIndex(of: viewController) else { return nil } if currentPageIndex == 0 { return nil } return pages[currentPageIndex - 1] } func pageViewController(_ pageViewController: UIPageViewController, viewControllerAfter viewController: UIViewController) -> UIViewController? { print("Trailing Swipe") guard let viewController = viewController as? ColouredViewController else { return nil } guard let currentPageIndex = pages.firstIndex(of: viewController) else { return nil } if currentPageIndex == pages.count - 1 { return nil } return pages[currentPageIndex + 1] } } extension PageContainerViewController: UIPageViewControllerDelegate {} class ColouredViewController: UIViewController { var backgroundColor: UIColor? init(backgroundColor: UIColor) { super.init(nibName: nil, bundle: nil) self.backgroundColor = backgroundColor } required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } override func viewDidLoad() { super.viewDidLoad() view.backgroundColor = backgroundColor } }
1
0
49
4w
[iOS 26 beta] UIScene migration with loadFileURL:allowingReadAccessToURL: has partial rendering for app BG launch
We're currently migrating from AppDelegate to UISceneDelegate due to console warnings . Our application's UI, which is built on a single webpage, functions correctly when launched in the foreground after this migration. However, we've encountered an issue with partial rendered UI components when launching the application from the background, such as upon receiving a VoIP call. During a background launch, the following delegate calls occur before the client attempts to load a local webpage: [08/07 16:25:49:037][ 0x101ea3910]<ALA_SIGNAL>: [OS-PLT] Exit -[AppDelegate application:didFinishLaunchingWithOptions:] [08/07 16:25:49:084][ 0x10c0c4140]<PushToTalk> [Pushnotif] [] <ALA_SIGNAL>: [OS-CCF] Enter -[PushNotificationManager pushRegistry:didReceiveIncomingPushWithPayload:forType:withCompletionHandler:] [08/07 16:25:49:098][ 0x101ea3910]Begin -[SceneDelegate scene:willConnectToSession:options:] [08/07 16:25:49:098][ 0x101ea3910]Exit -[SceneDelegate scene:willConnectToSession:options:] As part of client login process we load the index page in WebKit here: [08/07 16:25:50:977][ 0x101ea3910]<ALA_SIGNAL>: [PLT-OS] Enter -[SceneDelegate loadUI:] [UI Launch Reason = 1] Code: NSString *path = [[NSBundle mainBundle]pathForResource:@"index" ofType:@"html" inDirectory:@"www"]; NSURL *urlReq = [NSURL fileURLWithPath:path]; [webView loadFileURL:urlReq allowingReadAccessToURL:urlReq]; The problem we're observing is that the webpage is only partially rendering in this background launch scenario (Seen after brought to FG). Any insights or assistance you can provide would be greatly appreciated.
2
0
177
4w
iOS 26 UITabBar size issue
On iOS 26 not able to control size of UITabBar. Sharing code below. Colour is applying correctly but somehow _UITabBarPlatterView which turns out as TabBar is not extending; leaving spaces on left, right & bottom sides. class CustomTabBar: UITabBar { override init(frame: CGRect) { super.init(frame: frame) backgroundColor = .red let firstItem = UITabBarItem(title: "Home", image: UIImage(systemName: "house"), tag: 0) let secondItem = UITabBarItem(title: "Search", image: UIImage(systemName: "magnifyingglass"), tag: 1) let thirdItem = UITabBarItem(title: "Profile", image: UIImage(systemName: "person.circle"), tag: 2) items = [firstItem, secondItem, thirdItem] selectedItem = firstItem } required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } } class ViewController: UIViewController { let tabBar: CustomTabBar = { let tb = CustomTabBar() tb.translatesAutoresizingMaskIntoConstraints = false return tb }() override func viewDidLoad() { super.viewDidLoad() view.backgroundColor = .systemBackground view.addSubview(tabBar) NSLayoutConstraint.activate([ tabBar.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 25), tabBar.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -25), tabBar.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor) ]) } } when specifying height in CustomTabBar explicitly... func alignInternalSubViews() { subviews.forEach { subView in subView.translatesAutoresizingMaskIntoConstraints = false NSLayoutConstraint.activate([ subView.topAnchor.constraint(equalTo: topAnchor), subView.leadingAnchor.constraint(equalTo: leadingAnchor), subView.trailingAnchor.constraint(equalTo: trailingAnchor), subView.bottomAnchor.constraint(equalTo: bottomAnchor), subView.heightAnchor.constraint(equalToConstant: 62) ]) } } What should I need to do in order to get this capsule _UITabBarPlatterView and its subviews resize accordingly?
3
0
210
4w
`awakeFromNib` and Approachable Concurrency
When attempting to compile an existing project with Swift 6, default isolation set to MainActor and approachable concurrency enabled, all awakeFromNib functions lead to the following compile error: "Main actor-isolated instance method 'awakeFromNib()' has different actor isolation from nonisolated overridden declaration" I've seen articles before approachable concurrency stating that one remedy is to wrap code within the function with MainActor.assumeIsolated{ }. However, that no longer addresses the error. One combination of changes that removes the error is doing the following: nonisolated override func awakeFromNib() { super.awakeFromNib() MainActor.assumeIsolated { ... } } Honestly, that's a mess. Long term, we are looking to remove all these functions, but does anyone have a better solution?
3
0
107
Aug ’25