Hi,
I came across the following API:
@MainActor
func placeCursor(at position: UITextPosition!, animated: Bool)
From the signature, it seems intended to move the insertion point (caret) to a given UITextPosition, with an option for animation.
However, UITextView and UITextField don’t seem to expose this method as a public member — calling it gives the error:
Value of type 'UITextView' has no member 'placeCursor'
My questions are:
Is placeCursor(at:animated:) a public, supported API that we can safely use in apps?
If not, what is the Apple-recommended way to programmatically move the cursor without animation?
Right now, I only know of updating selectedTextRange, which works but doesn’t involve this placeCursor method. I want to confirm if placeCursor is meant for developer use or is an internal/private API.
Thanks!
UIKit
RSS for tagConstruct and manage graphical, event-driven user interfaces for iOS or tvOS apps using UIKit.
Posts under UIKit tag
200 Posts
Selecting any option will automatically load the page
Post
Replies
Boosts
Views
Activity
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.
I have been banging my head against this problem for a bit now.
I am trying to build a bidirectional, infinitely scrolling list that implements these core requirements:
Loads data up/down on the fly as the user scrolls
Preserves scroll velocity as the list is updated
Restores the scroll to the exact visual location after data has changed
Ensures no flicker when restoring scroll position - the user cannot know the list has updated and should continue scrolling as normal
Because LazyVStack does not play well with animations, I am opting to go with VStack and am implementing my own sliding window for data. This means that data can be removed as well as added, and a simple application of a height delta is not enough when restoring position.
So far I have tried many things:
Relying on ScrollPosition - simply does not work by itself as described (swift UI trying to keep the position stable with ID's)
Relying on ScrollPosition.scrollTo - only kind of works with ID, no way to restore position with pixel perfect accuracy
Intercepting the UIKit scrollView instance, using it to record and access the top row's position, mutating data and then queuing a scroll restoration using CATransaction.setCompletionBlock - this is the closest I've come, and it satisfies the top 3 requirements but sometimes I get a flicker on slightly heavier lists
What I would really like, is a way of using ScrollView and granularly hooking into the lifecycle of the view after layout, and just before draw. At this point I would update the relevant scroll positions, and allow draw to continue. Is this possible? My knowledge is very limited at this point, but I believe I may be able to achieve something of the sort by swizzling layerWillDraw? Does this make sense, and is it prudent?
In general, I'm very interesting in hearing what people have to say about the above, as well as this problem in general.
I’m trying to keep a specific row visually stable while the data backing a ScrollView changes.
Goal
1. Before updating model.items, capture the top row’s offset relative to the scroll view.
2. Mutate the observable state so SwiftUI recomputes layout — but don’t draw yet.
3. Read the new layout, compute the delta, and adjust the scroll position so the previously visible row stays put.
4. Only then draw the new frame.
Reduced example
@Observable
final class SomeModel {
var items: [SomeItem] = [/* ... */]
}
struct MyBox: View {
@Environment(SomeModel.self) private var model
var body: some View {
ScrollView {
VStack {
ForEach(model.items, id: \.id) { item in
Color.red.frame(height: randomStableHeight(for: item.id))
}
}
}
}
}
// Elsewhere:
let oldRow = recordOldRow() // capture the row to stabilize
model.items = generateNewItems() // mutate model (invalidates layout)
let newPos = capturePreviousRowNewPosition(oldRow) // read new layout?
restoreScrollPosition() // adjust so oldRow stays visually fixed
// draw now
Is that pipeline achievable in SwiftUI? If not, what’s the supported way to keep a row visually stable while the list updates?
I have installed the iOS 26 Beta on my device and conducted a comprehensive functionality test of my iOS application, which I designed and developed. The application includes a feature that allows users to share images directly to X (formerly Twitter) and Facebook.
During testing, I encountered an issue where the icons for X (formerly Twitter) and Facebook do not appear in the share dialog, despite both apps being installed on the device. This issue prevents users from sharing images to these platforms directly from the app.
Steps to Reproduce:
1.Install iOS 26 Beta on a compatible device.
2.Ensure that both the X (formerly Twitter) and Facebook apps are installed and logged in on the device.
3.Open the iOS application and navigate to the image sharing feature.
4.Attempt to share an image using the share dialog.
5.Observe that the icons for X (formerly Twitter) and Facebook are missing from the share options.
Expected Behavior:
The share dialog should display icons for X (formerly Twitter) and Facebook, allowing users to share images directly to these platforms.
Actual Behavior:
The icons for X (formerly Twitter) and Facebook do not appear in the share dialog, preventing direct sharing to these platforms.
Code Implementation:
I have not implemented any code to exclude X (formerly Twitter) and Facebook from the share options. Below is the relevant code for controlling the share screen:
let activityViewController = UIActivityViewController(activityItems: activityItems, applicationActivities: applicationActivities)
let excludedTypes = [
UIActivity.ActivityType.assignToContact,
UIActivity.ActivityType.print,
]
activityViewController.excludedActivityTypes = excludedTypes
activityViewController.completionWithItemsHandler = completion
self.present(activityViewController, animated: true, completion: nil)
As shown in the implementation, there is no exclusion of X (formerly Twitter) and Facebook, yet their icons do not appear in the share dialog.
Hello,
I'm facing issues when using prefersLargeTitles on iOS26, as you can see in the UI hierarchy, the largeTitle is assigned to a UINavigationBarLargeTitleView but not in the UINavigationBar. On the other hand, iOS18 we only have the navigationBar largeTitle.
Is this an identified issue, how can I fix it? We set the title and set prefersLargeTitles to true, do you know any reason this happens?
Additionally, if I set the navigationBar.isTranslucent to false the extra NavigationBarLargeView in the TableView is non-existent.
Thank you!
iOS26
iOS18
We're trying to implement a backup/restore data feature in our business productivity iPad app using UIDocumentPickerViewController and AppleArchive, but discovered odd behavior of [UIDocumentPickerViewController initForOpeningContentTypes: asCopy:YES] when reading large archive files from a USB drive.
We've duplicated this behavior with iPadOS 16.6.1 and 17.7 when building our app with Xcode 15.4 targeting minimum deployment of iPadOS 16. We haven't tested this with bleeding edge iPadOS 18.
Here's our Objective-C code which presents the picker:
NSArray* contentTypeArray = @[UTTypeAppleArchive];
UIDocumentPickerViewController* docPickerVC = [[UIDocumentPickerViewController alloc] initForOpeningContentTypes:contentTypeArray asCopy:YES];
docPickerVC.delegate = self;
docPickerVC.allowsMultipleSelection = NO;
docPickerVC.shouldShowFileExtensions = YES;
docPickerVC.modalPresentationStyle = UIModalPresentationPopover;
docPickerVC.popoverPresentationController.sourceView = self.view;
[self presentViewController:docPickerVC animated:YES completion:nil];
The UIDocumentPickerViewController remains visible until the selected external archive file has been copied from the USB drive to the app's local tmp sandbox. This may take several seconds due to the slow access speed of the USB drive. During this time the UIDocumentPickerViewController does NOT disable its tableview rows displaying files found on the USB drive. Even the most patient user will tap the desired filename a second (or third or fourth) time since the user's initial tap appears to have been ignored by UIDocumentPickerViewController, which lacks sufficient UI feedback showing it's busy copying the selected file.
When the user taps the file a second time, UIDocumentPickerViewController apparently begins to copy the archive file once again. The end result is a truncated copy of the selected file based on the time between taps. For instance, a 788 MB source archive may be copied as a 56 MB file. Here, the UIDocumentPickerDelegate receives a 56 MB file instead of the original 788 MB of data.
Not surprisingly, AppleArchive fails to decrypt the local copy of the archive because it's missing data. Instead of failing gracefully, AppleArchive crashes in AAArchiveStreamClose() (see forums post 765102 for details).
Does anyone know if there's a workaround for this strange behavior of UIDocumentPickerViewController?
I am observing an unexpected behavior with external keyboard input on iOS.
When I press Command + key (e.g., ⌘ + J) while a UITextView is focused, the system invokes
pressesBegan(_ presses: Set<UIPress>, with event: UIPressesEvent?)
twice:
-> Once with the key press event without any modifier flags.
-> A second time with the same key event but including the Command modifier flag.
This behavior is checked on an iPad with an external keyboard.
Additionally, I noticed that textView(_:shouldChangeTextIn:replacementText:) is not invoked in this case, even if I call super.pressesBegan for event propagation.
Questions:
Is it expected that pressesBegan fires twice for a Command + key combination?
If so, what is the recommended way to distinguish between these two invocations?
Should the UITextView delegate methods (like shouldChangeTextIn) be triggered for such key combinations, or is this by design?
When I set up UIScrollEdgeElementContainerInteraction for a UITableView in iOS 26 like this:
let interaction = UIScrollEdgeElementContainerInteraction()
interaction.scrollView = tableView
interaction.edge = .top
viewHeader.addInteraction(interaction)
the section header remains displayed above the gradient glass effect, but the cells do not exhibit this issue.
Visually, the cells appear beneath the glass layer, while the header appears above the glass layer—even though, in reality, both the header and the cells are positioned below the glass layer in the view hierarchy.
When I set up UIScrollEdgeElementContainerInteraction for a UITableView in iOS 26 like this:
let interaction = UIScrollEdgeElementContainerInteraction()
interaction.scrollView = tableView
interaction.edge = .top
viewHeader.addInteraction(interaction)
the section header remains displayed above the gradient glass effect, but the cells do not exhibit this issue.
Hello!
The minimize behavior was working correctly while I was using Xcode 26 beta 4 with iOS 26 beta 4 simulator — when scrolling down, the Tab Bar would minimize as expected.
However, after upgrading both Xcode and iOS simulator to beta 5, the tabBarMinimizeBehavior setting no longer has any visible effect — the Tab Bar stays fixed in place.
Code snippet:
if #available(iOS 26.0, *) {
self.tabBarMinimizeBehavior = .onScrollDown
}
Steps to reproduce:
1. Create a UITabBarController with at least one tab containing a scrollable view (e.g., UITableView).
2. In viewDidLoad, set tabBarMinimizeBehavior to .onScrollDown.
3. Run on iOS 26 beta 5 simulator.
Expected behavior (beta 4):
Scrolling down hides/minimizes the Tab Bar with animation.
Actual behavior (beta 5):
Tab Bar remains fixed; no minimize animation is triggered.
Environment:
• Xcode 26 beta 5 (Build: 17A5295f)
• iOS 26 beta 5 simulator (Build: 1055) – iPhone 16 Pro
• Also tested on iPhone 13 mini – iOS 26 (Build: 23A5308g)
Hi there. Our designer is designing our app in Figma with the navigation element with compact size navigation bar, and large title. I couldn't find an API to actually configure the nav bar to be compact while keeping the large title enabled. Figma uses the libraries provided by Apple so it's weird I can't find such configuration in iOS26.
I'm adding a screenshot of the options in Figma.
First option is: Large size & large text.
The one our designer is using is compact size & large text.
I'm trying to apply a CIBumpDistortion Core Image filter to a view that contains a UILabel (my storyLabel). The goal is to create a visual bump/magnifying glass effect over the text.
However, despite my attempts, the filter doesn't seem to render at all. The view and the label appear as normal, with no distortion effect. I've tried adjusting the filter parameters and reviewing the view hierarchy, but without success. I also haven't been able to find clear documentation or examples for applying this filter to a UIView's layer.
//
// TVView.swift
// Mistery
//
// Created by Joje on 31/07/25.
//
import CoreImage
import CoreImage.CIFilterBuiltins
import UIKit
import AVFoundation
final class TVView: UIView {
// propriedades animacao texto
private var textAnimationTimer: Timer?
private var fullTextToAnimate: String = ""
private var currentCharIndex: Int = 0
// propriedades video estatica
private var player: AVQueuePlayer?
private var playerLayer: AVPlayerLayer?
private var playerLooper: AVPlayerLooper?
var onNextButtonTap: () -> Void = {}
// MARK: - Subviews
// imagem da TV
private(set) lazy var tvImageView: UIImageView = {
let imageView = UIImageView()
imageView.translatesAutoresizingMaskIntoConstraints = false
imageView.image = UIImage(named: "tvFinal")
imageView.contentMode = .scaleAspectFit
return imageView
}()
// texto que passa dentro da TV
private(set) lazy var storyLabel: UILabel = {
let label = UILabel()
label.translatesAutoresizingMaskIntoConstraints = false
//label.backgroundColor = .gray
label.textColor = .red
label.font = UIFont(name: "MeltedMonster", size: 30)
label.textAlignment = .left
label.numberOfLines = 0
label.text = ""
return label
}()
private(set) lazy var nextButton: UIButton = {
let button = UIButton(type: .system)
button.translatesAutoresizingMaskIntoConstraints = false
//button.backgroundColor = .darkGray
button.addTarget(self, action: #selector(didPressNextButton), for: .touchUpInside)
return button
}()
// MARK: - Lifecycle
override init(frame: CGRect) {
super.init(frame: frame)
backgroundColor = .black
setupVideoPlayer()
addSubviews()
setupConstraints()
}
override func layoutSubviews() {
super.layoutSubviews()
playerLayer?.frame = tvImageView.frame.insetBy(dx: tvImageView.frame.width * 0.05, dy: tvImageView.frame.height * 0.18)
setupFisheyeEffect()
}
private func setupFisheyeEffect() {
// cria o filtro
guard let filter = CIFilter(name: "CIBumpDistortion") else {return print("erro")}
storyLabel.layer.shouldRasterize = true
storyLabel.layer.rasterizationScale = UIScreen.main.scale
// define os parametros
filter.setDefaults()
// centro do efeito
let center = CIVector(x: storyLabel.bounds.midX, y: storyLabel.bounds.midY)
filter.setValue(center, forKey: kCIInputCenterKey)
// raio de distorção
filter.setValue(storyLabel.bounds.width, forKey: kCIInputRadiusKey)
// intensidade de distorção
filter.setValue(7, forKey: kCIInputScaleKey)
storyLabel.layer.filters = [filter]
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
// MARK: - Button actions
@objc private func didPressNextButton() {
onNextButtonTap()
}
@objc private func animateNextCharacter() {
guard currentCharIndex < fullTextToAnimate.count else {
textAnimationTimer?.invalidate()
return
}
let currentTextIndex = fullTextToAnimate.index(fullTextToAnimate.startIndex, offsetBy: currentCharIndex)
let partialText = String(fullTextToAnimate[...currentTextIndex])
storyLabel.text = partialText
currentCharIndex += 1
}
public func updateStoryText(with text: String) {
textAnimationTimer?.invalidate()
storyLabel.text = ""
fullTextToAnimate = text
currentCharIndex = 0
textAnimationTimer = Timer.scheduledTimer(timeInterval: 0.12, target: self, selector: #selector(animateNextCharacter), userInfo: nil, repeats: true)
}
// MARK: - Setup methods
private func setupVideoPlayer() {
guard let videoURL = Bundle.main.url(forResource: "static-video", withExtension: "mov") else {
print("Erro: Não foi possível encontrar o arquivo de vídeo static-video.mov")
return
}
let playerItem = AVPlayerItem(url: videoURL)
player = AVQueuePlayer(playerItem: playerItem)
// LINHA COM POSSIVEL ERRO
playerLooper = AVPlayerLooper(player: player!, templateItem: playerItem)
playerLayer = AVPlayerLayer(player: player)
playerLayer?.videoGravity = .resizeAspectFill
if let layer = playerLayer {
self.layer.addSublayer(layer)
}
player?.play()
}
private func addSubviews() {
self.addSubview(storyLabel)
self.addSubview(tvImageView)
self.addSubview(nextButton)
}
private func setupConstraints() {
NSLayoutConstraint.activate([
// TV Image
tvImageView.centerXAnchor.constraint(equalTo: centerXAnchor),
tvImageView.centerYAnchor.constraint(equalTo: centerYAnchor),
tvImageView.widthAnchor.constraint(equalTo: widthAnchor),
// TV Text
storyLabel.centerXAnchor.constraint(equalTo: tvImageView.centerXAnchor, constant: -50),
storyLabel.centerYAnchor.constraint(equalTo: tvImageView.centerYAnchor, constant: -25),
storyLabel.widthAnchor.constraint(equalTo: tvImageView.widthAnchor, multiplier: 0.35),
storyLabel.heightAnchor.constraint(equalTo: tvImageView.heightAnchor, multiplier: 0.42),
//TV Button
nextButton.topAnchor.constraint(equalTo: tvImageView.centerYAnchor, constant: -25),
nextButton.centerXAnchor.constraint(equalTo: self.centerXAnchor, constant: 190),
nextButton.widthAnchor.constraint(equalToConstant: 100),
nextButton.heightAnchor.constraint(equalToConstant: 160)
])
}
}
#Preview{
ViewController()
}
I have an app that displays a MapView. While I am in light mode everything is fine. I can scroll around the map and my overlays (made by UIVisualEffectView containing an UIGlassEffect) stay light and look well!
As soon as I change my phone to dark mode, depending on what's underneath the buttons (a light residential area or darker wooded areas) some of my buttons change color. But not all, only where it's supposedly lighter or darker underneath. This makes my whole UI look strange. Some buttons bright, some dark.
Is there a way to lock a "color" or interfaceStyle to the effects-view? In light mode everything is fine, but in dark mode it just looks super strange.
We are using a column style split view controller as root view of our app and in iOS26 the navigation titles of primary and supplementary view controllers are not visible and secondary view controller title is displayed in supplementary column.
Looks the split view hidden all the child view controllers title and shown the secondary view title as global in macCatlayst. The right and left barbutton items are showing properly for individual view controllers.
Facing this weird issue in iOS26 betas. The secondary navigation title also visible only when WindowScene,titlebar.titleVisibility is not hidden.
Kindly suggest the fix for this issue as we can't use the secondary view navigation title for showing supplementary view's data. The issue not arises in old style split views or when the split view embedded in another splitView.
Refer the sample code and attachment here
let splitView = UISplitViewController(style: .tripleColumn)
splitView.preferredDisplayMode = .twoBesideSecondary
splitView.setViewController(SplitViewChildVc(title: "Primary"), for: .primary)
splitView.setViewController(SplitViewChildVc(title: "Supplementary"), for: .supplementary)
splitView.setViewController(SplitViewChildVc(title: "Secondary"), for: .secondary)
class SplitViewChildVc: UIViewController {
let viewTitle: String
init(title: String = "Default") {
self.viewTitle = title
super.init(nibName: nil, bundle: nil)
}
override func viewDidLoad() {
super.viewDidLoad()
self.title = viewTitle
self.navigationItem.title = viewTitle
if #available(iOS 26.0, *) {
navigationItem.subtitle = "Subtitle"
}
let leftbutton = UIBarButtonItem(barButtonSystemItem: .cancel, target: nil, action: nil)
navigationItem.leftBarButtonItem = leftbutton
let rightbutton = UIBarButtonItem(barButtonSystemItem: .add, target: nil, action: nil)
navigationItem.rightBarButtonItem = rightbutton
}
}
What is the recommended way to obtain the concentric corner radius for views within grouped UICollectionView cells?
In the most basic example, a UICollectionView with one section and one cell, we observe the cell takes almost the shape of a capsule, but it is indeed not a capsule.
What is the way to obtain the radius of the grouped area from within the cell or its registration? I would like to layer elements on top that are concentric to the cell's clip shape.
I've tried using custom views with .concentric UICornerConfigurations, setting .cornerConfiguration on the cell and on a custom backgroundView and I've even tried obtaining the .effectiveRadius of the cell after layout (returns 0.0). As of Xcode 26.0 Beta 7, nothing works.
This seems like a huge omission; what am I missing here?
Hello,
I hope you're all doing well! I'm currently working on integrating new iOS 26 features into my app, and so far, the process has been really exciting. However, I've encountered an issue when updating the badge of a UIBarButtonItem, and I’m hoping to get some insights or suggestions.
The app has two UIViewController instances in the navigation stack, each containing a UIBarButtonItem.
On the first controller, the badge is set to 1, and on the second, the badge is set to 2. In the second controller, there is a "Reset" button that sets the badge of the second controller to nil.
However, when I tap the "Reset" button, instead of setting the badge to nil, it sets the value to 1.
I would appreciate any ideas or suggestions on how to solve this problem. Maybe I am using the badge API incorrectly.
Thank you!
class ViewController: UIViewController {
var cartButtonItem: UIBarButtonItem!
override func viewDidLoad() {
super.viewDidLoad()
configureNavigationItem()
}
func configureNavigationItem() {
cartButtonItem = UIBarButtonItem(image: UIImage(resource: .cartNavBar), style: .plain, target: self, action: #selector(showCartTab))
cartButtonItem.tintColor = UIColor.systemBlue
cartButtonItem.badge = .count(1)
navigationItem.rightBarButtonItem = cartButtonItem
}
@objc func showCartTab() {
// Add second view controller in navigation stack
performSegue(withIdentifier: "Cart", sender: nil)
}
}
class CartViewController: UIViewController {
var cartButtonItem: UIBarButtonItem!
override func viewDidLoad() {
super.viewDidLoad()
configureNavigationItem()
}
func configureNavigationItem() {
cartButtonItem = UIBarButtonItem(image: UIImage(resource: .cartNavBar), style: .plain, target: nil, action: nil)
cartButtonItem.tintColor = UIColor.systemBlue
cartButtonItem.badge = .count(2)
navigationItem.rightBarButtonItem = cartButtonItem
}
func updateBadge() {
cartButtonItem.badge = nil
}
@IBAction func resetButtonPressed(_ sender: Any) {
updateBadge()
}
}
I want to be able to disable all liquid glass effects from my Navigation bar, and it's bar buttons. But I still want to be able to have the liquid glass effect on my UITabbar.
Is there a way to disable glass effects from navbar and still retain them all for tabbars using UIKit?
I’m trying to understand the exact role of the return value in the UITextFieldDelegate method textFieldShouldReturn(_:).
From my experiments in Xcode, I observed:
Returning true vs false does not seem to cause any visible difference (e.g., the keyboard does not automatically dismiss either way).
I know that in shouldChangeCharactersIn returning true allows the system to insert the character, and returning false prevents it. That’s clear.
For textFieldShouldReturn, my current understanding is that returning true means “let the OS handle the Return press,” and returning false means “I’ll handle it myself.”
My confusion: what is it that the OS actually does when it “handles” the Return press?
Does UIKit do anything beyond calling this delegate method?
If the system is supposed to dismiss the keyboard when returning true, why doesn’t it happen automatically?
I’d appreciate clarification on the expected use of this return value — specifically, what default behavior the system performs (if any) when we return true.
Thanks!
On testing my app with tvOS 18, I have noticed the Siri Remote back button no longer provides system-provided behavior when interacting with tab bar controller pages. Instead of moving focus back to the tab bar when pressed, the back button will close the app, as if the Home button was pressed. This occurs both on device and in the Simulator.
Create tvOS project with a tab bar controller.
Create pages/tabs which contain focusable items (ie. buttons)
Scroll down to any focusable item (ie. a button or UICollectionView cell)
Hit the Siri Remote back button. See expect behavior below:
Expected behavior: System-provided behavior should move focus back to the tab bar at the top of the screen.
Actual results: App is closed and user is taken back to the Home Screen.
Has anyone else noticed this behavior?