I have three custom UIButton instances inside a custom UIView subclass (not inside a UINavigationBar, UIToolbar, or UITabBar). I want to apply UIGlassEffect with interactive = YES to each button so they get the native liquid glass press animation.
The problem is that the UIVisualEffectView containing the effect either:
Has userInteractionEnabled = YES — glass animation works but the button's IBAction never fires
Has userInteractionEnabled = NO — IBAction fires but no glass animation
How can I have both the native interactive glass animation and the button action firing on the same button? Is this possible with the public API, or is the interactive glass animation on custom buttons simply not supported outside of standard UIKit controls?
Explore the various UI frameworks available for building app interfaces. Discuss the use cases for different frameworks, share best practices, and get help with specific framework-related questions.
Selecting any option will automatically load the page
Post
Replies
Boosts
Views
Activity
Hi,
In Apple Music on CarPlay, there is a Search button shown next to the Now Playing (NPS) button in the top navigation bar. Tapping this Search button activates Siri voice search.
I want to understand:
Does CarPlay allow third-party audio apps to add a similar Search button in the top bar (next to the Now Playing button)? Which can be used to trigger Siri from the screen UI (not steering-wheel button or “Hey Siri”)?
Is there any supported approach for screen-based Siri activation other than the guidance here: https://developer.apple.com/documentation/carplay/cplisttemplate#Integrating-Siri-Into-Your-Template-App
Basically, is the Apple Music search/Siri button a publicly available CarPlay capability, or is it system-reserved?
I am reporting a reproducible performance issue in iOS 18.6 where synchronizing the scroll position of two Chart views via chartScrollPosition(id:) causes a complete redraw loop when custom AxisMarks are used. This occurs even when the axis marks are technically "hidden," leading to significant frame drops and stuttering on modern hardware like the iPhone 15.
Environment
Device: iPhone 15
OS: iOS 18.6 (22G86)
Frameworks: SwiftUI, Swift Charts, Observation
The Issue
When using a shared @Observable state to sync two charts, the scrolling is fluid only if the axes are at their default settings. As soon as a custom AxisMarks block is added to either chart, the following behavior is observed:
Diffing Failure:
The framework appears unable to maintain the identity of the axis components during the scroll update.
Redraw Loop:
Instead of an incremental scroll translation, the diffing algorithm triggers a full reload/re-render of both charts on every scroll offset change.
Impact: CPU spikes to 100% and the UI becomes unresponsive.
This happens even if the custom AxisMarks is used solely to hide the axis (e.g., AxisMarks { _ in }), suggesting the issue is with the custom declaration itself rather than the complexity of the marks being rendered.
Steps to Reproduce
Create two Chart views in a VStack.
Bind both to a single @Observable property using .chartScrollPosition(id: $state.pos).
Add any .chartXAxis { AxisMarks(...) { ... } } modifier.
Scroll either chart; observe the stuttering.
import SwiftUI
import Charts
import Observation
@Observable class ChartState {
var scrollPos: Date = .now
}
struct PerformanceBugView: View {
@State private var state = ChartState()
var body: some View {
VStack {
Chart(data) { ... }
.chartScrollPosition(id: $state.scrollPos)
.chartXAxis {
// This custom mark triggers the performance issue
AxisMarks { _ in AxisValueLabel() }
}
Chart(data) { ... }
.chartScrollPosition(id: $state.scrollPos)
}
}
}
Questions for the Community/Apple Engineers:
Is there a way to provide a stable identifier to AxisMarks to prevent them from being treated as "new" during a scroll update?
Why does even an empty AxisMarks block (used for hiding) trigger a layout invalidation that standard axes do not?
Are there internal optimizations for chartScrollPosition that are bypassed when the axis layout is customized?
My app is a UIKit app with a lot of SwiftUI mixed in. A common scenario is that a UIViewController presents a sheet with a SwiftUI view wrapped in a UIHostingController.
When I present the exact same SwiftUI View it looks different in a SwiftUI sheet compared to when it's wrapped in a UIHostingController and presented from a view controller.
I'm using a hacky workaround in which I loop through all subviews of the hosting controller in viewWillLayoutSubviews and look for a NavigationStackHostingController<SwiftUI.AnyView> to manually set the background color, but it feels like it could brake easily.
Has anyone found a better way to fix this?
Feedback: FB22028838
To display rows and columns of data in a nice layout like a spreadsheet I use a table like the code here ..
Table(array) {
TableColumn("Ticker", value: \\.ticker)
TableColumn("Other", value: \.other)
}
To delete a row from the table the advice is to use a ForEach loop. Since I don’t use a ForEach loop, how do I delete rows from the table ? With this code there is no way to attach a .onDelete modifier or a Button
Any advice would be much appreciated
Thank you
Topic:
UI Frameworks
SubTopic:
SwiftUI
Here’s a recap of the Live Q&A for SwiftUI foundations: Build great apps with SwiftUI. If you participated and asked questions, thank you for coming and participating! If you weren’t able to join us live we hope this recap is useful
Where can I watch the VOD? Is the sample code “Wishlist” that was shown available for download?
You can view the replay of the entire event here https://www.youtube.com/watch?v=Z3vloOtZLkQ
The sample code for the Wishlist app will be made available in the coming weeks on the Apple Developer website, we'll send an update via email when it is available.
What are the best practices when it comes to building complex navigations in SwiftUI?
The developer website has documentation on navigation style best practices.
Explore navigation basics like NavigationStack and TabView to get a ground-up understanding. For documentation on navigation APIs see Navigation.
How can I integrate UIKit with my SwiftUI app? What about adding SwiftUI into my UIKit app?
See UIKit integration: Add UIKit views to your SwiftUI app, or use SwiftUI views in your UIKit app. Both UIKit and SwiftUI provide API to show a view hierarchy of the other.
For UIKit to SwiftUI, you would use UIViewControllerRepresentable.
For SwiftUI to UIKit, you would use UIHostingController.
Landmarks: Interfacing with UIKit walks you through step by step how to implement UIKit in SwiftUI with UIViewControllerRepresentable, and this WWDC22 video demonstrates UIHostingController, for those that want to add SwiftUI to their UIKit.
Does Wishlist feature a new iOS 26 font? How can I add custom fonts and text of my app?
We’re glad to hear many of you liked wide text shown in Wishlist, however, It is the default system font with some light SwiftUI styling! Check it out for yourself in the sample code when made available, and you can learn more about customizing fonts and text by seeing Font and Applying custom fonts to text.
Does Xcode have a dependency graph we can use to optimize our SwiftUI Views?
Xcode comes with Instruments. Instruments is the best way to figure out what is causing excessive updates and other issues with performance. That link provides direct tutorials and resources for how to use and understand. Previews also have many useful tools for analyzing SwiftUI views, for more info see Previews in Xcode
Check out this video from our latest WWDC Optimize SwiftUI performance with Instruments for information on how to use Instruments to profile and optimize your app with real-world applications
If you still have questions, Check out the Instruments section of these forums and create a post so the community has the opportunity to help guide you.
Are there UI debugging tools to help diagnose layout issues?
Yes, Xcode also features a View Debugger located by selecting the View Debug Hierarchy, pictured below. Use the View Debugger to capture and inspect your view hierarchy, identifying which views affect window sizing. The SwiftUI Inspector also lets you examine view frames and layout behavior.
See Diagnosing issues in the appearance of a running app to learn about debugging visual and layout issues.
As an absolute beginner, what would be the first go-to step to go for training? Do I need prior knowledge of frameworks to get started with SwiftUI?
A great place to learn how to develop for Apple platforms is with Pathways! Many developers start with Develop in Swift tutorials, which exposes you to several frameworks while teaching you the basics of SwiftUI. When you're ready to take your learning further, you can read the documentation for the specific frameworks that interest you at https://developer.apple.com/documentation/.
Topic:
UI Frameworks
SubTopic:
SwiftUI
I reported Korean IME bug to QT Bug report. Please refer to below link.
https://bugreports.qt.io/browse/QTBUG-136128?jql=text%20~%20korean%20ORDER%20BY%20created%20DESC
But, QT reponsed me like follwing.
Thank you for reporting. However, this issue seems like a known issue with apple's Korean IME. There are many threads in Korean community about the same problem with Non-Qt apps. If this issue is a really Qt issue, feel free to open it again.
Is there any workaround to fix this IME bug ?
Thanks,
Ted
My application provides a unique feature for MacOS 26+ users, while keeping legacy for other versions (12.4+).
So I aim to provide two help books localized package, depending on MacOS' version of the running computer.
I designed two help bundles, with their own Info.plist files (identifiers, default filename…) and I've made multiple checks to verify that all their settings are correct and different when needed.
As an app's info.plist can deal only with one Help Book, my application delegate registers both in
applicationDidFinishLaunching:
using:
[[NSHelpManager sharedHelpManager] registerBooksInBundle:[NSBundle mainBundle]];
In Interface Builder, the help menu item is connected to the application delegate's "showHelp:" method to set the correct help package. The code in this method is:
if (@available(macOS 26.0,*)){
helpbook = @"fr.myapp.updated.help";
} else {
helpbook = @"fr.myapp.legacy.help";
}
[[NSHelpManager sharedHelpManager] openHelpAnchor:@"index" inBook:helpbook];
The problem is that despite the MacOS version of the user's Mac, (either 15.1 or 26.2) , the «legacy» helpbook is always used. All default index.html (for each lproj) have a
tag immediately after the
I spent dozen of hours to understand the problem, forum parsing, including hours long dialogs with ChatGPT and Claude AIs (not mentioning MacOS' help system cache problems I could solve)
I noticed also, to be complete, that when parsing the application package, opening the legacy .help with "Tips.app" always works, but with the "updated" one the help system opens with an "unavailable content" message. Both help bundles are fully included in the built application.
Tested whether the app is installed in the debug directory, moved to in the Applications one, reboot, emptying/deleting cache files.
So Houston, I have a problem…
Any idea?
Topic:
UI Frameworks
SubTopic:
AppKit
When making an element with .glassEffect(.clear.interactive()) draggable, it stretches as it moves.
It seems like it's meant to stretch as you move your finger away from the element, but it doesn't make sense if the element is following your finger as you drag it.
Is this a bug, or is there a way to disable this behavior without removing the other "interactive" animations?
P.S. The shiny border around the elements seems to be a rounded rectangle or capsule, but the actual element's shape seems to be stretched. That also appears to be a bug.
I'm building a macOS app that uses WKWebView for text editing (not NSTextView). I need to provide grammar checking by calling NSSpellChecker programmatically and sending results back to the web editor.
The problem: TextEdit (which uses NSTextView) catches grammar errors like "Can I has pie?" and "These are have" — but when I call NSSpellChecker's APIs directly, those same errors are never flagged.
I've tried both APIs:
1. The unified check() API:
let results = checker.check(
text, range: range,
types: NSTextCheckingAllTypes,
options: [:],
inSpellDocumentWithTag: tag,
orthography: &orthography,
wordCount: &wordCount)
This returns only .orthography results (language detection). No .spelling, no .grammar — just orthography.
2. The dedicated checkGrammar(of:startingAt:...) API:
let sentenceRange = checker.checkGrammar(
of: text,
startingAt: offset,
language: nil,
wrap: false,
inSpellDocumentWithTag: tag,
details: &details)
This catches sentence fragments ("The.", "No.") and some agreement errors ("The is anyone.") but misses "Can I has pie?", "These are have", "This will be happened", and other subject-verb agreement errors that TextEdit highlights.
What I've confirmed:
"Check Grammar With Spelling" is enabled in System Settings
TextEdit reliably catches all these errors with green underlines
Both APIs are called with a valid spellDocumentTag from uniqueSpellDocumentTag()
The text is passed as plain strings (no attributed string context)
My question: How does NSTextView's grammar checking work internally? It must be using something beyond these two public APIs. Possibilities I'm considering:
Does NSTextView use the NSTextCheckingClient protocol / requestChecking(of:range:types:options:) for asynchronous checking that produces different results?
Does NSTextView provide additional context (attributed string, layout info) that improves grammar detection?
Is there a private/undocumented API or framework that NSTextView uses for deeper grammar analysis?
Any insight from anyone who has implemented programmatic grammar checking on macOS would be appreciated.
NOTE: This post was composed with the help of Claude Code, which I am using to help write a word-processing application, but I am frustrated because Claude Code wants to give up and switch to a 3rd party grammar checker, like LanguageTool, and it seems to me that it should be possible to use native Apple tools to achieve this goal without requiring the user to send their data elsewhere for checking. I've spent a lot of time searching the web for answers and have found surprisingly little on this. Any pointers people might have would be very much appreciated! Thanks.
I'm experiencing consistent memory crashes in iOS 26.3 (23D127)
when using @AppStorage with view transitions.
Environment:
Device: iPhone 17 Pro Max
iOS: 26.3 (23D127)
Xcode: 26.2 (17C52)
Issue:
App crashes with "Terminated due to memory issue" when:
Using @AppStorage to manage state
Calling UserDefaults.set() in completion handler
Transitioning to new view based on changed state
Workaround:
Using @State instead of @AppStorage prevents crash.
Feedback: FB############ (your number)
Has anyone else experienced this? Is this a known issue in iOS 26?
Topic:
UI Frameworks
SubTopic:
SwiftUI
I read some article that said for using Apple Intelligence as an integrated part of an app, instead of tacked on, MVVM and VIPER are not good fits. Would that be accurate? What other architectures could work better? (The author didn’t suggest any replacements.)
.navigationDestination(isPresented) hangs after reboot (when called within 2 minutes of reboot) in watchOS when destination view contains @Environment(.dismiss).
Feedback: FB21077151
Second button hangs after reboot. Hangs in watchOS 26.0 and 26.4 on a physical device.
struct ContentView: View {
@State var presentView1 : Bool = false
@State var presentView2 : Bool = false
var body: some View {
NavigationStack {
VStack {
Button("Show View 1") {
presentView1.toggle()
}
Button("Show View 2") {
presentView2.toggle()
}
}
.navigationDestination(isPresented: $presentView1, destination: {TestView1()})
.navigationDestination(isPresented: $presentView2, destination: {TestView2()})
}
}
}
struct TestView1: View {
var body: some View {
Text("View 1")
}
}
struct TestView2: View {
@Environment(\.dismiss) var dismiss
var body: some View {
Text("View 2")
}
}
I’ve encountered an aspect of the Liquid Glass effect in SwiftUI that seems a bit odd: the Liquid Glass interaction appears to ignore regular hit-testing behavior.
The following sample shows a button with hit testing disabled:
@main
struct LiquidGlassHitTestDemo: App {
var body: some Scene {
WindowGroup {
Button("Liquid") {
fatalError("Never called.")
}
.buttonStyle(.glassProminent)
.allowsHitTesting(false)
}
}
}
As expected, the button’s action is never called. However, the interactive glass effect still responds to touch events:
What’s even more surprising is that the UIKit equivalent behaves differently:
final class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let button = UIButton(
configuration: .prominentGlass(),
primaryAction: UIAction(
title: "Liquid",
handler: { action in
print("Never called.")
}
)
)
view.addSubview(button)
button.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
button.centerXAnchor.constraint(equalTo: view.centerXAnchor),
button.centerYAnchor.constraint(equalTo: view.centerYAnchor)
])
button.isUserInteractionEnabled = false
}
}
In this case, the effect is not interactive at all. Similarly, if a UIViewController’s root view overrides hitTest(_:with:) to always return nil, the Liquid Glass effect does not react to touch events whatsoever.
The only way I’ve found to “properly” disable the glass interactivity in SwiftUI is to use the .disabled(true) modifier. However, this also changes the button’s appearance, which is not always desirable.
Is this expected behavior, or could this be a bug? Am I missing something about how Liquid Glass interaction is implemented in SwiftUI?
MacOS system settings allow the user to select one of a number of number formats. My app behaves differently depending on the format (taken from the system Locale), so I need to test every combination.
Thus far I have been successful at creating Locale objects with various identifiers that map to the different formats, like:
let westEuropeanLocale = Locale(identifier: "en_DE")
However, I can't find a locale that maps to using . as a decimal point, and space as a thousands separator, even though it's a standard option (3rd in this list):
Any suggestions on how to create a test for this number format?
When you set inputAccessoryView AND inputView you get unexpected system UI in between the two custom views
If anyone has a workaround for this I'd love to hear it.
See also: https://stackoverflow.com/questions/79818015/uitextfield-custom-inputaccessoryview-with-custom-inputview-in-ios-26
Red == inputAccessoryView
Blue == inputView
Glassy bit in between == bug?
//
// ViewController.swift
// Custom Keyboard
//
// Created by Lewis Smith on 19/02/2026.
//
import UIKit
class ViewController: UIViewController {
let textField = {
let textField = UITextField()
textField.translatesAutoresizingMaskIntoConstraints = false
textField.backgroundColor = .yellow
let inputAccessoryView = UIView(frame: CGRect(x: 0, y: 0, width: .zero, height: 70))
inputAccessoryView.backgroundColor = .red
let inputView = UIView(frame: CGRect(x: 0, y: 0, width: .zero, height: 70))
inputView.backgroundColor = .blue
// When you set inputAccessoryView AND inputView you get unexpected UI inbetweeen the two custom views
textField.inputAccessoryView = inputAccessoryView
textField.inputView = inputView
textField.becomeFirstResponder()
return textField
}()
override func viewDidLoad() {
super.viewDidLoad()
self.view.backgroundColor = .purple
self.view.addSubview(textField)
NSLayoutConstraint.activate([
textField.centerXAnchor.constraint(equalTo: view.centerXAnchor),
textField.centerYAnchor.constraint(equalTo: view.centerYAnchor),
textField.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 20),
textField.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -20),
])
}
}
It appears that starting with macOS Sequoia, Quick Look Preview extension no longer loads MapKit maps correctly anymore. Map tiles do not appear, leaving users with a beige background.
Users report that polylines do render correctly, but annotations appears black.
This was previously working fine in prior macOS versions including Sonoma.
STEPS TO REPRODUCE
Create a macOS app project, with an associated document.
Ensure project has a Quick Look preview extension, with necessary basic setups.
Ensure that the extension mentioned in (2) must have a MKMapView. Any other cosmetic changes, etc, does not need to be implemented to observe the base issue. Do note that it has been reported that in addition to the map tiles not loading, annotations don't render correctly as well.
Do you guys know how to fix the render of the text in the accessory view ? If I force the color of text to be .black it work but it will break dark mode, but forcing it .black : .white on color scheme changes makes white to still adapt to what is behind it I have noticed that Apple Music doesn’t have that artifact and it seems to break when images are behind the accessory view
// MARK: - Next Routine Accessory
@available(iOS 26.0, *)
struct NetxRoutinesAccessory: View {
@ObservedObject private var viewModel = RoutineProgressViewModel.shared
@EnvironmentObject var colorSchemeManager: ColorSchemeManager
@EnvironmentObject var routineStore: RoutineStore
@EnvironmentObject var freemiumKit: FreemiumKit
@ObservedObject var petsStore = PetsStore.shared
@Environment(\.colorScheme) private var colorScheme
// Tab accessory placement environment
@Environment(\.tabViewBottomAccessoryPlacement) private var accessoryPlacement
// Navigation callback
var onTap: (() -> Void)?
@State private var isButtonPressed = false
/// Explicit black for light mode, white for dark mode
private var textColor: Color {
colorScheme == .dark ? .trueWhite : .trueBlack
}
/// Returns true when the accessory is in inline/minimized mode
private var isInline: Bool {
accessoryPlacement == .inline
}
var body: some View {
accessoryContent()
.onTapGesture {
onTap?()
}
}
private func accessoryContent() -> some View {
HStack(spacing: 12) {
// Content with smooth transitions
VStack(alignment: .leading, spacing: 2) {
if viewModel.totalTasks == 0 {
Text(NSLocalizedString("Set up routines", comment: "Routines empty state"))
.font(.subheadline.weight(.medium))
.foregroundColor(textColor)
} else if let next = viewModel.nextRoutineTask() {
HStack(spacing: 4) {
Text(NSLocalizedString("Next", comment: "Next routine prefix"))
.font(.caption)
.foregroundColor(textColor)
Text("•")
.font(.caption)
.foregroundColor(textColor)
Text(next.routine.name)
.font(.subheadline.weight(.medium))
.foregroundColor(textColor)
.lineLimit(1)
}
.id("routine-\(next.routine.id)-\(next.time)")
.transition(.opacity.combined(with: .move(edge: .leading)))
HStack(spacing: 4) {
Text(viewModel.petNames(for: next.routine.petIDs))
.font(.caption)
.foregroundColor(textColor)
Text("•")
.font(.caption)
.foregroundColor(textColor)
Text(Routine.displayTimeFormatter.string(from: next.time))
.font(.caption.weight(.medium))
.foregroundColor(colorSchemeManager.accentColor ?? .blue)
}
.id("time-\(next.routine.id)-\(next.time)")
.transition(.opacity.combined(with: .move(edge: .leading)))
} else {
// All tasks completed
Text(NSLocalizedString("All done for today!", comment: "All routines completed"))
.font(.subheadline.weight(.medium))
.foregroundColor(textColor)
.transition(.opacity.combined(with: .scale))
Text("\(viewModel.completedTasks)/\(viewModel.totalTasks) " + NSLocalizedString("tasks", comment: "Tasks count suffix"))
.font(.caption)
.foregroundColor(textColor)
}
}
.animation(colorSchemeManager.reduceMotion ? nil : .snappy(duration: 0.3), value: viewModel.completedTasks)
.animation(colorSchemeManager.reduceMotion ? nil : .snappy(duration: 0.3), value: viewModel.progress)
}
.padding()
.contentShape(.rect)
.animation(colorSchemeManager.reduceMotion ? nil : .snappy(duration: 0.35), value: viewModel.completedTasks)
}
}
Topic:
UI Frameworks
SubTopic:
SwiftUI
When disabling the opacity slider of color panels, my app crashes with unsatisfiable layout constraints. Feel free reproduce with a minimal test project: A macOS app based on the Xcode 26.0 template with only one line added to the ViewController's viewDidLoad() function:
NSColorPanel.shared.showsAlpha = false
The issue doesn't occur if this property is set to "true" or not set at all.
I just filed a corresponding bug report (FB20269686), although I don't expect any feedback from Apple ... as numerous issues I reported were never updated or commented at all (after migrating from RADARs).
Topic:
UI Frameworks
SubTopic:
AppKit
I'm developing a turn-based Messages game extension and experiencing a persistent issue on iPad where tapping on message bubbles does not reliably trigger lifecycle callbacks after the extension has been used once.
The Problem:
On iPad, after a player:
Opens the extension by tapping a game message
Takes their turn (plays a card)
Sends the updated game state as a new message
Extension collapses
When the opponent sends their response and the player taps on the new message bubble, the extension often does not open. The didSelect(_:conversation:) method is not called. The user must refresh the conversation by scrolling away and back or reopening the Messages App before tapping works again. This works perfectly on iPhone - every tap on a message bubble reliably triggers didSelect and opens the extension.
What I've Tried:
I've implemented every lifecycle method and workaround I could find:
swiftoverride func willBecomeActive(with conversation: MSConversation) {
super.willBecomeActive(with: conversation)
if let message = conversation.selectedMessage, let url = message.url {
loadGameState(from: url, message: message, conversation: conversation)
}
}
override func didBecomeActive(with conversation: MSConversation) {
super.didBecomeActive(with: conversation)
if let message = conversation.selectedMessage, let url = message.url {
loadGameState(from: url, message: message, conversation: conversation)
}
}
override func didSelect(_ message: MSMessage, conversation: MSConversation) {
// This is NOT called on iPad when tapping message bubbles
guard let url = message.url else { return }
loadGameState(from: url, message: message, conversation: conversation)
}
override func didReceive(_ message: MSMessage, conversation: MSConversation) {
guard let url = message.url else { return }
loadGameState(from: url, message: message, conversation: conversation)
}
override func didTransition(to presentationStyle: MSMessagesAppPresentationStyle) {
super.didTransition(to: presentationStyle)
// Attempted to reload here as well
}
I also tried:
Observing NSExtensionHostDidBecomeActive and NSExtensionHostWillEnterForeground notifications
Forcing UI refresh in viewDidLayoutSubviews
Checking conversation.selectedMessage in every lifecycle method
Research:
I found several Developer Forums threads from 2016 describing this exact issue:
Thread 53167: "MSMessagesAppViewController.didSelect not called on message reselect"
Thread 60323: "willSelectMessage and didSelectMessage don't fire"
An Apple staff member confirmed that didSelect only fires when selecting a different message, similar to UITableView selection behavior. However, on iPad, it seems like messages remain "selected" even after the extension collapses, so tapping a new message doesn't register as a new selection.
Questions:
Is there a recommended way to detect when a user taps a message bubble on iPad, even if iOS considers a message "already selected"?
Is there a way to programmatically deselect the current message (similar to UITableView.deselectRow) so that subsequent taps trigger didSelect?
Are there any iPad-specific lifecycle methods or notifications I should be observing?
Is this a known limitation of the Messages framework on iPad?
Environment:
Xcode 16
iOS 18 and 26
Testing on iPad Pro (M4) and iPad Air
iPhone works correctly on all tested devices
Any guidance would be greatly appreciated. This is blocking our App Store submission as reviewers are flagging the iPad behavior as incomplete functionality.