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

Do we need to explicitly register all high-level interaction events for every widget in UIKit?
I have a question about how UIKit expects us to handle interaction events at scale. From what I understand so far: For UIControls (UIButton, UISwitch, UITextField, etc.), we explicitly register with addTarget(_:action:for:). For gestures, we add UIGestureRecognizer instances to views. For UIView subclasses, we can override touch methods like touchesBegan/touchesEnded. All of this must be done on the main thread, since UIKit isn’t thread-safe. Now here’s my main concern If I have a complex UI with hundreds or thousands of widgets, am I expected to perform these registrations individually for each widget and each high-level event (tap, long press, editing changed, etc.)? Or does UIKit provide a more centralized mechanism? In short: Is per-widget, per-event registration the “normal” UIKit approach, or are there best practices for scaling event handling without writing thousands of addTarget or addGestureRecognizer calls? Thanks!
Topic: UI Frameworks SubTopic: UIKit Tags:
3
0
91
2w
Summary of iOS/iPadOS 26 UIKit bugs related to UISearchController & UISearchBar using scope buttons
All of these issues appear when the search controller is set on the view controller's navigationItem and the search controller's searchBar has its scopeButtonTitles set. So far the following issues are affecting my app on iOS/iPadOS 26 as of beta 7: When the scopeBarActivation of UISearchController is set to .onSearchActivation, the preferredSearchBarPlacement of the navigationItem is set to .integratedButton, and the searchBarPlacementAllowsToolbarIntegration is set to false (forcing the search icon to appear in the nav bar), on both iPhones and iPads, the scope buttons never appear. They don't appear when the search is activated. They don't appear when any text is entered into the search bar. FB19771313 I attempted to work around that issue by setting the scopeBarActivation to .manual. I then show the scope bar in the didPresentSearchController delegate method and hide the scope bar in the willDismissSearchController. On an iPhone this works though the display is a bit clunky. On an iPad, the scope bar does appear via the code in didPresentSearchController, but when any scope bar button is tapped, the search controller is dismissed. This happens when the app is horizontally regular. When the app on the iPad is horizontally compact, the buttons work but the search bar's text is not correctly aligned within the search bar. Quite the mess really. I still need to post a bug report for this issue. But if issue 1 above is fixed then I don't need this workaround. When the scopeBarActivation of UISearchController is set to .onSearchActivation, the preferredSearchBarPlacement of the navigationItem is set to .stacked, and the hidesSearchBarWhenScrolling property of the navigationItem is set to false (always show the search bar), and this is all used in a UITableViewController, then upon initial display of the view controller on an iPhone or iPad, you are unable to tap on the first row of the table view except on the very bottom of the row. The currently hidden scope bar is stealing the touches. If you activate and then cancel the search (making the scope bar appear and then disappear) then you are able to tap on the first row as expected. The initially hidden scope bar also bleeds through the first row of the table. It's faint but you can tell it's not quite right. Again, this is resolved by activating and then canceling the search once. FB17888632 When the scopeBarActivation of UISearchController is set to .onSearchActivation, the preferredSearchBarPlacement of the navigationItem is set to integrated or .integratedButton, and the toolbar is shown, then on iPhones (where the search bar/icon appears in the toolbar) the scope buttons appear (at the top of the screen) the first time the search is activated. But if you cancel the search and then activate it again, the search bar never appears a second (or later) time. On an iPad the search bar/icon appears in the nav bar and you end up with the same issue as #1 above. FB17890125 Issues 3 and 4 were reported against beta 1 and still haven't been fixed. But if issue 1 is resolved on iPhone, iPad, and Mac (via Mac Catalyst), then I personally won't be affected by issues 2, 3, or 4 any more (but of course all 4 issues need to be fixed). And by resolved, I mean that the scope bar appears and disappears when it is supposed to each and every time the search is activated and cancelled (not just the first time). The scope bar doesn't interfere with touch events upon initial display of the view controller. And there are no visual glitches no matter what the horizontal size class is on an iPad. I really hope the UIKit team can get these resolved before iOS/iPadOS 26 GM.
1
1
105
2w
UITabBarController bottom accessory doesn't resize properly when horizontal size class changes from compact to regular
A bottom accessory view is set on the UITabBarController. When changing the window size either by dragging the resizing grip or when going to portrait mode, the accessory view shrinks down to the smaller width. When resizing the window to make it larger, the accessory view doesn’t resize to the full available width. During a workshop setup by Apple, folks from Apple told me that the view set as the content view of the UITabAccessory should not have its frame changed, either by using Auto Layout or by setting the frame. It seems logical since the view in the bottom accessory is supposed to resize accordingly to several factors, like when going inline inside the tab bar. Am I missing something? Maybe there is additional setup required not mentioned in the dedicated video. Feedback is FB19017330. It contains a sample project and videos demonstrating the issue. Reproduced on Xcode 26 beta 6 (17A5305f) I copy and paste the sample code that setups the bottom accessory for good measure. final class MiniPlayer: UIView { let label = UILabel() override init(frame: CGRect) { super.init(frame: frame) label.text = "Mini Player" label.numberOfLines = 0 label.textAlignment = .center addSubview(label) label.translatesAutoresizingMaskIntoConstraints = false NSLayoutConstraint.activate([ label.centerXAnchor.constraint(equalTo: centerXAnchor), label.centerYAnchor.constraint(equalTo: centerYAnchor) ]) } required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } } // MARK: - View Controller class ViewController: UIViewController { let rootTabBarController = UITabBarController() let miniPlayer = MiniPlayer() override func viewDidLoad() { super.viewDidLoad() let items: [UITab] = [ UITab(title: "Tab 1", image: UIImage(systemName: "archivebox.fill"), identifier: "tab-1") { _ in UIViewController() }, UITab(title: "Tab 2", image: UIImage(systemName: "books.vertical.fill"), identifier: "tab-2") { _ in UIViewController() }, UISearchTab { _ in UIViewController() } ] rootTabBarController.tabs = items rootTabBarController.view.backgroundColor = .secondarySystemBackground view.addSubview(rootTabBarController.view) rootTabBarController.view.translatesAutoresizingMaskIntoConstraints = false NSLayoutConstraint.activate([ rootTabBarController.view.leadingAnchor.constraint(equalTo: view.leadingAnchor), rootTabBarController.view.topAnchor.constraint(equalTo: view.topAnchor), rootTabBarController.view.trailingAnchor.constraint(equalTo: view.trailingAnchor), rootTabBarController.view.bottomAnchor.constraint(equalTo: view.bottomAnchor) ]) rootTabBarController.bottomAccessory = UITabAccessory(contentView: miniPlayer) } }
0
0
148
2w
UIScene.ConnectionOptions.shouldHandleActiveWorkoutRecovery Missing?
According to the WWDC25 Presentation Track workouts with HealthKit on iOS and iPadOS, there is supposed to be a new property for restoring an active workout after a crash on iOS/iPadOS. The developer documentation also supports this. However, this property does not seem to exist in the latest Xcode 26 beta, even in projects targeting iOS 26.0 as the minimum version. Am I missing something? Has this property not been made available yet? It is actually looking like all of the new iOS 26.0 properties are missing UIScene.ConnectionOptions on my system.
3
0
134
2w
UISlider valueChanged has uninitialized UIEvent
This issue was in the first iOS 26 beta and it still there with Xcode 26 beta 6 (17A5305f). Feedback is FB18581605 and contains sample project to reproduce the issue. I assign a target and action to a UISlider for the UIControl.Event.valueChanged value: addTarget(self, action: #selector(sliderValueDidChange), for: .valueChanged) Here’s the function. @objc func sliderValueDidChange(_ sender: UISlider, event: UIEvent) { print(event) } When printing the event value, there is a crash. When checking the event value with lldb, it appears uninitialized.
Topic: UI Frameworks SubTopic: UIKit Tags:
7
2
234
2w
SF Symbol variable draw doesn't work in UIKit
I tried playing with SF Symbols variable value draw from the first iOS 26 beta and it has never been working, whereas the SwiftUI version works properly. I just copied and pasted the code from the related video What’s new in SF Symbols 7 and it simply doesn't work (screenshot attached). Full view controller code is at the end of the post. imageView.image = UIImage(systemName: "thermometer.high", variableValue: 0.5) imageView.preferredSymbolConfiguration = UIImage.SymbolConfiguration(variableValueMode: .draw) Am I missing something? Or is it still not ready? I reproduced the issue with Xcode 26 beta 6 (17A5305f). The release candidates are approaching fast and I am worried this will not be working by then. The feedback ID is FB18898182. class ViewController: UIViewController { let imageView = UIImageView() override func viewDidLoad() { super.viewDidLoad() imageView.image = UIImage(systemName: "thermometer.high", variableValue: 0.5) imageView.preferredSymbolConfiguration = UIImage.SymbolConfiguration(variableValueMode: .draw) .applying(UIImage.SymbolConfiguration(font: .systemFont(ofSize: 40))) view.addSubview(imageView) imageView.translatesAutoresizingMaskIntoConstraints = false NSLayoutConstraint.activate([ imageView.centerXAnchor.constraint(equalTo: view.centerXAnchor), imageView.centerYAnchor.constraint(equalTo: view.centerYAnchor) ]) } }
1
0
115
2w
Has Background Refresh Stopped Working on watchOS 26?
Hi everyone! My Apple Watch app has relied for years on the WKApplication.scheduleBackgroundRefresh(...) method to keep the app updated in the background. The system would reliably trigger WKApplicationDelegate.handle(_:), where I would then schedule the next refresh task (usually 15 minutes later). As stated in the documentation, as long as there is a complication on the watch face, these background tasks should run at a relatively stable frequency. However, this approach seems to have stopped working on watchOS 26. I no longer receive any WKApplicationRefreshBackgroundTask at all. Has anyone else experienced this issue?
2
0
93
2w
How to reduce cell height (vertical margins) when using UIListContentConfiguration
The default cell height is 44pt in iOS 18 and 52pt in iOS 26. I'm trying to reduce the height back to 44pt in one screen that needs to fit as much content on screen as possible. How do you do that when using UIListContentConfiguration? I expected this would do the trick but alas it doesn't reduce the cell height. let cellRegistration = UICollectionView.CellRegistration<UICollectionViewListCell, Item> { cell, indexPath, item in cell.contentConfiguration = { var config = UIListContentConfiguration.valueCell() config.text = "Title" config.secondaryText = "Value" // This only removes horizontal margins, does not change vertical margins config.axesPreservingSuperviewLayoutMargins = [] config.directionalLayoutMargins = .zero return config }() }
Topic: UI Frameworks SubTopic: UIKit Tags:
4
0
107
2w
[iOS 26] UIVideoEditorController preview's top bar is overlapping with parent view controller
Applicaiton is built with WebKit and native camera view controller . Issue is seen always when presenting a UIVideoEditorController class on top of MainVC(webKit). Please refer the attached image Code: self.videoEditor.modalPresentationStyle = UIModalPresentationFullScreen; [viewController presentViewController:self.videoEditor animated: YES completion:nil];
3
0
92
2w
Recommended Approach for Handling Multiple UIButton Events: Single Handler vs Multiple Selectors?
I’m working with UIButton and finding different examples for event handling. Currently, I have a single action method like this, which receives the sender and the UIEvent: @objc func buttonHandler(_ sender: UIButton, forEvent event: UIEvent) { if let touches = event.allTouches, let touch = touches.first { switch touch.phase { case .began: print("TouchDown") case .ended: if sender.bounds.contains(touch.location(in: sender)) { print("TouchUpInside") } else { print("TouchUpOutside") } case .cancelled: print("TouchCancel") default: break } } if event.type == .presses { print("PrimaryActionTriggered") } } Is this considered best/recommended practice in UIKit, or should I use separate selector methods for each event type (e.g. .touchDown, .touchUpInside, .touchUpOutside) using addTarget(_:action:for:)? Are there any advantages or disadvantages to using a single handler with UIEvent versus multiple selectors for UIControlEvents? Thanks in advance!
Topic: UI Frameworks SubTopic: UIKit Tags:
0
0
47
2w
How to identify which UIControl.Event triggered a common selector for UIButton?
I’m working with UIButton and I’d like to register multiple UIControl.Events (e.g. .touchUpInside, .touchDown, .touchCancel, .primaryActionTriggered) using the same selector. For example: button.addTarget(self, action: #selector(handleButtonEvent(_:forEvent:)), for: [.touchUpInside, .touchDown, .touchCancel, .primaryActionTriggered]) @objc func handleButtonEvent(_ sender: UIButton, forEvent event: UIEvent) { // How do I tell which UIControl.Event triggered this? } From my understanding: If I use the single-parameter version (@objc func handleButtonEvent(_ sender: UIButton)), I can’t distinguish which event fired. If I use the two-parameter version with UIEvent, I can inspect touch.phase or event.type, but that feels indirect. Questions: Is there a recommended way to directly know which UIControl.Event caused the selector to fire? Is sharing a single selector across multiple control events considered a good practice, or is it more common to register separate selectors per event? Would appreciate guidance on what Apple recommends here.
Topic: UI Frameworks SubTopic: UIKit Tags:
1
0
39
2w
Recommended way to detect double-tap on UIButton and scope of UIControl.Event
I’m trying to detect a double-tap action on a UIButton. There seem to be two possible approaches: Using a UITapGestureRecognizer with numberOfTapsRequired = 2. Using the .touchDownRepeat event of UIControl.Event. What is the recommended approach for reliably handling double-taps on UIButton? Are there any practical differences in terms of behavior, performance, or best practices between these two methods? Additionally, I noticed that UIControl.Event defines a large set of events (like .editingChanged, .valueChanged, etc.). Can all these events be applied to any UIControl subclass such as UIButton, or are they only valid for specific controls like UITextField, UISlider, etc.? If not all events are supported by all controls, what is the rationale behind exposing them under a shared UIControl.Event enum? Thanks in advance!
Topic: UI Frameworks SubTopic: UIKit Tags:
3
0
59
2w
New window scenes on iPad always take the size of the activating window
I'm using multiple scenes in my iPad app. When I open a new scene from my main window, that new window is always the same size as the previous window. When I make the main window very small and then create a new scene, that new window is also tiny. When I make the main window very big, you guessed it. UIWindowScene.sizeRestrictions does not seem to help here. How can I give new windows a default size (it's okay if they're resizable after presenting)? This is such a weird behavior. Video of the problem in action: https://mastodon.social/@nicoreese/115033539035249909
Topic: UI Frameworks SubTopic: UIKit Tags:
1
0
115
3w
App lifecycle on iPadOS 26
It appears from my testing that the following is true: If you close all windows of an app, the app terminates entirely. Minimizing the last window sends it into multitasking. This is different from previous behavior and might have implications on your app's logic. If you close the last window and quickly tap the app icon again, that same window will come back. Waiting a second before tapping the app icon will bring up the main window (likely because by that point the app was terminated and relaunched). Is this expected behavior? I did not see any announcement of this. I find this a bit counterintuitive and would presume that closing the last window would just send the app to multitasking, just like previously. Quitting the app should be reserved by swiping up on it in the multitasking UI or with a new context menu command.
Topic: UI Frameworks SubTopic: UIKit Tags:
0
0
56
3w
iOS 26, bottom UIToolbar not extending behind safe area to screen edge
An app with a UIToolbar pinned to the bottom of a view controllers view extends to the screen edge (behind the safe area) when run on iOS 18.X but not iOS 26. This UIToolbar is set as constrained to the safeAreaLayoutGuide with the following constraints. self.view.addConstraints([ bottomToolbar.leadingAnchor.constraint(equalTo: self.view.leadingAnchor), bottomToolbar.trailingAnchor.constraint(equalTo: self.view.trailingAnchor), bottomToolbar.bottomAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.bottomAnchor), bottomToolbar.heightAnchor.constraint(greaterThanOrEqualToConstant: 44.0) ]) This is especially noticeable when the UIToolbar background color differs from the view background color. This occurs on iOS 26 beta 6, app built with Xcode 26 beta 5. I've posted a Feedback FB19664903 including a minimal Xcode workspace that reproduces this issue. Anyone suggestions would be appreciated ... this definitely seems like a regression.
3
1
175
3w
iOS 26 UIBarButtonItems in navigation bar flashing wrong background during push/pop
An iOS app has a UINavigationController with a UINavigationBar that is non-translucent (e.g. black). When performing a push (or pop) to navigate to or from another UIViewController the UIBarButtonItems on the navigation bar are flashing a white background. With a dark navigation bar this is very noticeable and not desirable. This only occurs when run on iOS 26 and is related to Liquid Glass I've created FB19660024 with a minimal Xcode workspace to reproduce, along with a video showing the behavior. This is a cosmetic bug, not affecting functionality, but is a very undesirable effect on apps with dark and non-translucent navigation bars. Has anyone else seen this and found a workaround?
3
2
146
3w
How to correctly use UIWindow.canResizeToFitContent
Can anyone show a simple code snippet about the usage of this property? I tried to create a UIWindow inside the main window, and set the canResizeToFitContent to true. However, when I added to it some sub view, the sub view didn't fit into the UIWindow. Actually, this sub view was located in another place far away from the UIWindow I created. Additionally, The documentation says, the content should be constraint-based. What does 'constraint-based' mean?
Topic: UI Frameworks SubTopic: UIKit
0
0
78
3w
Best practices to use low-latency feature in UIUpdateLink?
Hi everyone, I'm not an experienced developer. I'm interested in the low-latency related APIs in UIUpdateLink, but I failed to write even a minimal demo that works. UIUpdateInfo.isImmediatePresentationExpected is always false here. My understanding must be wrong. I've totally no idea so I'm asking for help here. I appreciate anyone who gives suggestions of any kind. Here's my (failed) demo about tracking touch inputs (of the 1st finger) and draw some shape at that place: import UIKit class ContentUIView: UIView { // MARK: - About UIUpdateLink and drawing required init?(coder: NSCoder) { super.init(coder: coder) initializeUpdateLink() } override init(frame: CGRect) { super.init(frame: frame) initializeUpdateLink() } private func initializeUpdateLink() { self.updateLink = UIUpdateLink(view: self) self.updateLink.addAction(to: .beforeCADisplayLinkDispatch, target: self, selector: #selector(update)) self.updateLink.wantsImmediatePresentation = true self.updateLink.isEnabled = true } @objc func update(updateLink: UIUpdateLink, updateInfo: UIUpdateInfo) { print(updateInfo.isImmediatePresentationExpected) // FIXME: Why always false? CATransaction.begin() defer { CATransaction.commit() } layer.setNeedsDisplay() layer.displayIfNeeded() } override func draw(_ rect: CGRect) { // FIXME: Any way to support opacity? guard let context = UIGraphicsGetCurrentContext() else { return } context.clear(rect) guard let lastTouch = self.lastTouch else { return } let location = lastTouch.location(in: self) let circleBounds = CGRect(x: location.x - 16, y: location.y - 16, width: 32, height: 32) context.setFillColor(.init(red: 1/2, green: 1/2, blue: 1/2, alpha: 1)) context.addLines(between: []) context.fillEllipse(in: circleBounds) } // MARK: - Touch input override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) { super.touchesBegan(touches, with: event) guard lastTouch == nil else { return } lastTouch = touches.first } override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) { super.touchesEnded(touches, with: event) guard let lastTouch, touches.contains(lastTouch) else { return } self.lastTouch = nil } override func touchesCancelled(_ touches: Set<UITouch>, with event: UIEvent?) { self.touchesEnded(touches, with: event) } private var lastTouch: UITouch? private var updateLink: UIUpdateLink! } #Preview { ContentUIView() } Anyway, I'm not meant to find alternative APIs and I'd be willing to know what it can't do.
0
0
66
3w