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.

All subtopics
Posts under UI Frameworks topic

Post

Replies

Boosts

Views

Activity

List reordering animation broken in iOS 26
just opened a iOS18 project in latest Xcode 26 (beta 7) and the list reordering animation is broken and jerky. on iOS 18 a change to one of the list items would smoothly move it to its correct place but in iOS 26 the items jerk around, disappear then pop up in the correct order in the list. I am using this to filter and sort the "events" if searchQuery.isEmpty { return events.sort(on: selectedSortOption) } else { let filteredEvents = events.compactMap { event in // Check if the event title contains the search query (case-insensitive). let titleContainsQuery = event.title.range(of: searchQuery, options: .caseInsensitive) != nil return titleContainsQuery ? event : nil } return filteredEvents.sort(on: selectedSortOption) } } is there a better way for iOS 26?
Topic: UI Frameworks SubTopic: SwiftUI
0
0
159
6d
UIBarButtonItem Doesn't Reset the Badge
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() } }
0
0
62
6d
CarPlay: CPListTemplate item limit and image memory usage
I’m working with CPListTemplate in CarPlay and have run into two issues: Item limit: The documentation states that maximumItemCount is 500. In practice, when providing a list of ~2–4k items, only the first 500 are displayed. However, Apple Music on CarPlay seems to handle larger lists without this limitation. Is there an API-level approach or recommended pattern to support lists beyond this cap? Image memory usage: Cells don’t appear to load lazily. Even with small images, the first 500 items load all their artwork into memory immediately, resulting in ~400–700 MB usage and high CPU loads. This seems excessive for CarPlay environments. Is there a best practice for deferring or managing image loading within CPListTemplate? Any official guidance or known workarounds for these two issues would be very helpful.
0
0
74
6d
HideAllTips launch argument does not work in xctestplan
The launch argument -com.apple.TipKit.HideAllTips 1 does not work if it is defined in xctestplan arguments passed on launch. I tested it with the apple provided example app, where I created simple UI test and added xctestplan with launch argument -com.apple.TipKit.HideAllTips 1. The app does not hide the tips when it is running the UI Tests. Is there any solution that works? Thanks for reply.
2
0
38
6d
VisionKit – Tab Bar Button Titles Not Visible and Extra Back Button in iPad Landscape Mode
Description We observed multiple UI issues in VisionKit (VNDocumentCameraViewController) on iPad devices running iPadOS 26 (from Public Beta 4 onwards): Tab bar button titles are not properly visible due to color/contrast issues. An extra back button appears in the navigation bar when editing a captured image in landscape mode. These issues seem to be iPadOS 26 bugs, as Apple does not provide public APIs to customize or override VNDocumentCameraViewController. VisionKit relies on private ICDocCam* classes, which are not accessible for modification. Steps to Reproduce Open the app on an iPad running iPadOS 26 (Public Beta 4 or later). Switch the device to landscape mode. Launch document scanning using VNDocumentCameraViewController. Capture a document and tap Keep Scan. Go to the edit captured image screen. Observed Behavior: Tab bar button titles are not clearly visible (color/contrast issue). An extra back button is displayed in the navigation bar.
0
0
26
6d
How to access launchOptions in SceneDelegate?
Previously, when using AppDelegate, I was able to check the app’s launch options (launchOptions) to determine cases such as: Location updates (UIApplication.LaunchOptionsKey.location) Background push notifications (UIApplication.LaunchOptionsKey.remoteNotification) However, after migrating to the SceneDelegate approach, launchOptions is no longer available — it always returns nil. In my app, I need to branch the code depending on the launch options, but I can’t find a way to achieve this in the SceneDelegate environment. 👉 Is there a way to access launch options in SceneDelegate, similar to how it worked in AppDelegate? Or, if that’s no longer possible, what would be the proper alternative approach? Any guidance would be greatly appreciated.
2
0
96
6d
Touch Input Offset and Unresponsive Elements in iOS 18.6 (Xcode 16.4)
PLATFORM AND VERSION iOS Development environment: Xcode 16.4, macOS 15.6 Run-time configuration: iOS 18.6 DESCRIPTION OF PROBLEM Hi, We recently noticed some issues when running our existing app, even after applying updates, on iOS 18.6. The problem occurs both on the Xcode simulator and on clients’ mobile devices running iOS 18.5 or later. However, devices running versions below 18.5, such as iOS 18.4 (including iPads), do not experience this issue. The issue we are experiencing is that when we touch certain elements, they do not respond unless we tap slightly higher than the intended point. Please see the video in the link below. I believe others are also experiencing similar touch-related issues, though not identical to ours. On iOS 18.4: Works as expected. On iOS 18.6: The range bar cannot be moved unless we tap slightly above it, and once the map is displayed, the toggle button becomes non-functional. This behaviour is not present in any earlier iOS version. I suspect something may have changed in the OS that is causing this issue, possibly related to plugins, or perhaps something in Xcode that needs to be updated. We would greatly appreciate your guidance in resolving this matter. STEPS TO REPRODUCE Please see the following videos 18.4, performing as expected. https://screenrec.com/share/ASczNx0MRh 18.6, with issues https://screenrec.com/share/MR4VpyIBks 18.6 with the issue
Topic: UI Frameworks SubTopic: General
4
0
142
1w
Menu's primaryAction:{} is broken on latest iOS 26 beta
The following shows minimal example to reproduce the issue: Menu { Button("Test"){} } label: { Text("Menu") } primaryAction: { // Some action } primaryAction modifier will not be called when pressing the menu button/view on iOS 26 beta, long pressing it will open the menu. Was tested on latest iOS 26 beta 8
Topic: UI Frameworks SubTopic: SwiftUI
3
1
159
1w
Inconsistent subviews redrawing in LazyVStack
Hello Apple forum ! I spotted a weird behaviour with LazyVStack in a ScrollView. I understand that it loads its views only once upon appearance unlinke VStack that loads everything in one shot. What I noticed also, it seems to reload its views sometimes when scrolling back up to earlier loaded views. The thing is, it isn't always the case. struct LazyVStackTest: View { var body: some View { ScrollView { LazyVStack { ForEach(0..<1000, id: \.self) { _ in // if true { MyText() // } } } } } struct MyText: View { var body: some View { let _ = Self._printChanges() HStack { Text("hello") } } } } If we consider the code above on XCode 26 beta 7 on an iOS 26 or iOS 18.2 simulator. Scroll to the bottom : you'll see one "LazyVStackTest.MyText: @self changed" for each row. Then scroll back up to the top, we'll see again the same message printed multiple times. --> So I gather from this that LazyVStack not only loads lazily but also removes old rows from memory & recreates them upon reappearance. What I don't get however is that if you uncomment the "if true" statement, you won't see the reloading happening. And I have absolutely no clue as to why 😅 If someone could help shed some light on this weird behaviour, it would be greatly appreciated ^^ PS : the issue is also present with XCode 16.2 but at a deeper lever (ex: if we embed another custom View "MyText2" inside "MyText", the reloading is in "MyText2" & not "MyText")
0
0
131
1w
TextEditor Problem Or Me?
When using SwiftUI's TextEditor, the application crashes immediately on launch. This occurs even in a brand new project with the simplest usage. If I remove the TextEditor, the application runs normally. Environment: OS: macOS 15.6.1 Xcode: 16.4 SDK: macOS 14 (and also tried with macOS 15 SDK) Steps to Reproduce: Create a new SwiftUI macOS App project. Replace ContentView with the following code: import SwiftUI struct ContentView: View { @State private var text = "114514" var body: some View { TextEditor(text: $text) } } Run the app. Expected Result: The app should display a working TextEditor. Actual Result: The app immediately crashes, and the debugger shows a Metal assertion error. If I remove the TextEditor, the app works fine. Screenshot: Additional Notes: This issue did not occur on macOS 14 / Xcode 15.4. It reproduces even in an empty project. Possibly related to SwiftUI/Metal integration on macOS 15.6.1. 這樣寫更專業、清楚,Apple 工程師能快速重現和定位問題。 如果你要用中文回報也可以,我能幫你翻譯。
Topic: UI Frameworks SubTopic: SwiftUI
2
0
87
1w
NavigationStack path is being reset in NavigationSplitView details columns
I'm building a SwiftUI app for iPad using a NavigationSplitView as the navigation root. Below is a simplified version of the app's navigation. There are a Home Page and a Settings Page, each with its own NavigationStack. The page that appears in the detail column depends on the sidebar's selection value. The issue I'm facing is that when I navigate deeply into the Home Page's NavigationStack (e.g., to a Home Page Child view), switch to the Settings Page, and then switch back to the Home Page, the Home Page's navigation path has been reset to [] and the previous state is lost. The same issue occurs if I navigate deeply into the Settings Page (e.g., to a Settings Page Child view), switch to the Home Page, and then return to the Settings Page: the navigation state for the Settings Page is lost, and it reverts to the root of the NavigationStack. Why is this happening and how can I fix it so that switching pages in the sidebar doesn't reset the NavigationStack of each individual page in the detail column? Thank you. struct ContentView: View { @State var selection: String? @State var firstPath = [String]() @State var secondPath = [String]() var body: some View { NavigationSplitView { List(selection: $selection) { Text("Home") .tag("home") Text("Settings") .tag("settings") } } detail: { if selection == "home" { HomePage(path: $firstPath) } else { SettingsPage(path: $secondPath) } } } } struct HomePage: View { @Binding var path: [String] var body: some View { NavigationStack(path: $path) { NavigationLink("Home Page", value: "Home") .navigationDestination(for: String.self) { _ in Text("Home Page Child") } } } } struct SettingsPage: View { @Binding var path: [String] var body: some View { NavigationStack(path: $path) { NavigationLink("Settings Page", value: "Settings") .navigationDestination(for: String.self) { _ in Text("Settings Page Child") } } } } #Preview { ContentView() }
0
0
228
1w
SwiftUI TextField with optional value working for @State but not @Binding properties
I've encountered a potential bug where a TextField connected to an optional value (not a string) works as expected when bound to a @State property, but won't update a @Binding property. Here is some example code import SwiftUI struct ContentView: View { @Binding var boundValue: Double? @State private var stateValue: Double? = 55 var body: some View { TextField("Bound value", value: $boundValue, format: .number) Text("\(boundValue ?? .nan)") TextField("State value", value: $stateValue, format: .number) Text("\(stateValue ?? .nan)") } } #Preview { ContentView(boundValue: .constant(42.00)) } It's as though the optional value stored externally is preventing the value updating. Can anyone confirm whether this is intentional, or a bug? This is in Xcode 26b6, on macOS Tahoe 26b8, but from this query it looks like the problem has existed for years.
Topic: UI Frameworks SubTopic: SwiftUI
8
0
311
1w
UIMenuBuilder - some menus refuse customization
I'm trying to customize the menu in my iPad app for iOS 26, since most of the default menu options aren't relevant to my app. Fortunately, I already have the code for this from my Mac Catalyst implementation. However, the functionality to replace menus with new sets of options has no effect on some menus on iOS. For example, updating the Format menu works fine on Mac Catalyst and iOS 26: override func buildMenu(with builder: UIMenuBuilder) { super.buildMenu(with: builder) let transposeUpItem = UIKeyCommand(title: NSLocalizedString("TRANSPOSE_UP"), image: nil, action: #selector(TransposeToolbar.transposeUp(_:)), input: "=", modifierFlags: UIKeyModifierFlags.command, propertyList: nil, alternates: []) let transposeDownItem = UIKeyCommand(title: NSLocalizedString("TRANSPOSE_DOWN"), image: nil, action: #selector(TransposeToolbar.transposeDown(_:)), input: "-", modifierFlags: UIKeyModifierFlags.command, propertyList: nil, alternates: []) let transposeGroup = UIMenu(title: "", image: nil, identifier: UIMenu.Identifier(rawValue: "transposeGroup"), options: UIMenu.Options.displayInline, children: [transposeUpItem, transposeDownItem]) let boldItem = UIKeyCommand(title: NSLocalizedString("BOLD"), image: nil, action: #selector(FormatToolbar.bold), input: "b", modifierFlags: UIKeyModifierFlags.command, propertyList: nil, alternates: []) let italicItem = UIKeyCommand(title: NSLocalizedString("ITALIC"), image: nil, action: #selector(FormatToolbar.italic), input: "i", modifierFlags: UIKeyModifierFlags.command, propertyList: nil, alternates: []) let underlineItem = UIKeyCommand(title: NSLocalizedString("UNDERLINE"), image: nil, action: #selector(FormatToolbar.underline), input: "u", modifierFlags: UIKeyModifierFlags.command, propertyList: nil, alternates: []) let colorItem = UIKeyCommand(title: NSLocalizedString("COLOR"), image: nil, action: #selector(FormatToolbar.repeatColor), input: "c", modifierFlags: [.command, .alternate], propertyList: nil, alternates: []) let clearItem = UIKeyCommand(title: NSLocalizedString("CLEAR_FORMATTING"), image: nil, action: #selector(FormatToolbar.clear), input: "x", modifierFlags: [.command, .alternate], propertyList: nil, alternates: []) let formatGroup = UIMenu(title: "", image: nil, identifier: UIMenu.Identifier(rawValue: "formatGroup"), options: UIMenu.Options.displayInline, children: [boldItem, italicItem, underlineItem, colorItem, clearItem]) let markerItem = UIKeyCommand(title: NSLocalizedString("ADD_A_MARKER"), image: nil, action: #selector(FormatToolbar.marker), input: "m", modifierFlags: [.command, .alternate], propertyList: nil, alternates: []) let markerGroup = UIMenu(title: "", image: nil, identifier: UIMenu.Identifier(rawValue: "markerGroup"), options: UIMenu.Options.displayInline, children: [markerItem]) var formatMenu = builder.menu(for: .format) var formatItems = [transposeGroup, formatGroup, markerGroup] formatMenu = formatMenu?.replacingChildren(formatItems) if let formatMenu = formatMenu { builder.replace(menu: .format, with: formatMenu) } } The same approach for the View menu works fine on Mac Catalyst, but has no effect on iOS 26. I see the same View menu options as before: override func buildMenu(with builder: UIMenuBuilder) { super.buildMenu(with: builder) let helpItem = UIKeyCommand(title: NSLocalizedString("HELP"), image: nil, action: #selector(utilityHelp), input: "1", modifierFlags: UIKeyModifierFlags.command, propertyList: nil, alternates: []) let actionItemsItem = UIKeyCommand(title: NSLocalizedString("ACTION_ITEMS"), image: nil, action: #selector(utilityActionItems), input: "2", modifierFlags: UIKeyModifierFlags.command, propertyList: nil, alternates: []) let remoteControlItem = UIKeyCommand(title: NSLocalizedString("APP_CONTROL_STATUS"), image: nil, action: #selector(utilityRemoteControl), input: "3", modifierFlags: UIKeyModifierFlags.command, propertyList: nil, alternates: []) let midiItem = UIKeyCommand(title: NSLocalizedString("MIDI_STATUS"), image: nil, action: #selector(utilityMidi), input: "4", modifierFlags: UIKeyModifierFlags.command, propertyList: nil, alternates: []) let linkingItem = UIKeyCommand(title: NSLocalizedString("LIVE_SHARING_STATUS"), image: nil, action: #selector(utilityLinking), input: "5", modifierFlags: UIKeyModifierFlags.command, propertyList: nil, alternates: []) let syncItem = UIKeyCommand(title: NSLocalizedString("SYNCHRONIZATION"), image: nil, action: #selector(utilitySync), input: "6", modifierFlags: UIKeyModifierFlags.command, propertyList: nil, alternates: []) let settingsItem = UIKeyCommand(title: NSLocalizedString("SETTINGS"), image: nil, action: #selector(utilitySettings), input: "7", modifierFlags: UIKeyModifierFlags.command, propertyList: nil, alternates: []) let utilityGroup = UIMenu(title: "", image: nil, identifier: UIMenu.Identifier(rawValue: "utilityGroup"), options: UIMenu.Options.displayInline, children: [helpItem, actionItemsItem, remoteControlItem, midiItem, linkingItem, syncItem, settingsItem]) let backItem = UIKeyCommand(title: NSLocalizedString("BUTTON_BACK"), image: nil, action: #selector(navigateBack), input: UIKeyCommand.inputLeftArrow, modifierFlags: UIKeyModifierFlags.command, propertyList: nil, alternates: []) let mainMenuItem = UIKeyCommand(title: NSLocalizedString("MAIN_MENU"), image: nil, action: #selector(navigateMain), input: UIKeyCommand.inputLeftArrow, modifierFlags: [.command, .alternate], propertyList: nil, alternates: []) let navigateGroup = UIMenu(title: "", image: nil, identifier: UIMenu.Identifier(rawValue: "navigateGroup"), options: UIMenu.Options.displayInline, children: [backItem, mainMenuItem]) var viewMenu = builder.menu(for: .view) var viewItems = [utilityGroup, navigateGroup] viewMenu = viewMenu?.replacingChildren(viewItems) if let viewMenu = viewMenu { builder.replace(menu: .view, with: viewMenu) } } I tried a couple other approaches, but they also did nothing: var viewMenu = builder.menu(for: .view) var viewItems = [utilityGroup, navigateGroup] builder.replaceChildren(ofMenu: .view, from: { oldChildren in viewItems }) Also: viewMenu = UIMenu(title: NSLocalizedString("VIEW"), image: nil, identifier: .view, options: UIMenu.Options.displayInline, children: viewItems) if let viewMenu = viewMenu { builder.replace(menu: .view, with: viewMenu) } Does anyone know how to make this work for the View menu? It's frustrating that Apple added all these default options, without an easy way to remove options that aren't relevant.
Topic: UI Frameworks SubTopic: UIKit
3
0
292
1w
Wrong tint on CPMapButton in iOS 26
In my CarPlay app my CPMapButton with system images have the wrong tint when the CarPlay appearance is set to "Always Dark". Here is what it looks like. When I change the system appearance to "Automatic" the buttons look fine. Has anyone encountered this or know how to fix it?
Topic: UI Frameworks SubTopic: UIKit Tags:
1
0
83
1w
UtilityWindow can't read @FocusedValue of main scene
According to the UtilityWindow documentation: • They receive FocusedValues from the focused main scene in an application, similar to commands in the main menu, which can be used to display information on the active content as the user focuses on different scenes. This makes me think that any UtilityWindow, even across Scenes, should always receive @FocusedValues from the currently focused window of any scene. However, the following code doesn't quite work: @Observable class Info: Identifiable { let id = UUID() } struct ExampleApp: App { var body: some Scene { WindowGroup { ContentView() // Inside, it uses .focusedSceneValue(info) } UtilityWindow("Test") { UtilityWindowContent() } } } struct UtilityWindowContent: View { @FocusedValue(Info.self) var info var body: some View { Text(info?.id ?? "<nil>") // This always shows "<nil>" } } Here's some annotated screenshots of what's happening in a project: Menu bar commands do work with the same setup: As a workaround, attempting to use @FocusedValue in the App struct works, but as a result, the value appears to instantiate multiple times in the background, and they re-instantiate with every focus change. The @FocusedValue variable gets the correct instance, but it's needlessly initializing others in the background. This is on macOS 26.0 Tahoe Beta 8 (25A5349a).
0
0
94
1w
Concentric corner radius for grouped cells in UICollectionView on iOS 26
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?
1
0
115
1w
Charts SectorMark causing app to crash
Anytime I have 1 item, then add another, the app crashes with the following error: Swift/IntegerTypes.swift:8835: Fatal error: Double value cannot be converted to Int because it is either infinite or NaN I'm not working with Int values though, so I'm not sure why this is happening. It's also not point me towards any specific line. I've printed out all of the values being used for the chart and none of them are showing as infinite or NaN. The data being used is created in a View. @State private var pieChartData: [PieChartDataPoint] = [] Then in the onAppear and onChange its gets loaded using the following function: func getPieChartDataPoints() -> [PieChartDataPoint] { self.map({ PieChartDataPoint(label: $0.name, value: $0.monthlyAmount()) }) } That's an extension on a SwiftData model type I have called Recurring. @Model final class Recurring { var id = UUID() enum Kind: String, CaseIterable, Codable { case income = "Income" case bill = "Bill" func plural() -> String { switch self { case .income: "Income" case .bill: "Bills" } } } enum Frequency: String, CaseIterable, Codable, Identifiable { var id: Frequency { self } case weekly = "Weekly" case biweekly = "Biweekly" case monthly = "Monthly" case quarterly = "Quarterly" case annually = "Annually" } var name: String = "" var kind: Kind = Kind.income var frequency: Frequency = Frequency.biweekly var amount: Double = 0 init(name: String, kind: Kind, frequency: Frequency, amount: Double) { self.name = name self.kind = kind self.frequency = frequency self.amount = amount } func amount(from cycle: Cycle) -> Double { switch cycle { case .weekly: monthlyAmount() * 12 / 52 case .biweekly: monthlyAmount() * 12 / 26 case .monthly: monthlyAmount() } } func monthlyAmount() -> Double { switch frequency { case .weekly: amount * 52 / 12 case .biweekly: amount * 26 / 12 case .monthly: amount case .quarterly: amount * 4 / 12 case .annually: amount / 12 } } } Here is the DataPoint structure. struct PieChartDataPoint: Identifiable, Equatable { var id = UUID() var label: String var value: Double } Finally here is the chart. Chart(sorted, content: { dataPoint in SectorMark( angle: .value(dataPoint.label, getValue(from: dataPoint)), innerRadius: 50, angularInset: 5 ) .foregroundStyle(by: .value("Label", dataPoint.label)) .cornerRadius(10) .opacity(getSectorMarkOpacity(for: dataPoint)) }) .scaledToFill() .chartLegend(.hidden) .chartAngleSelection(value: $chartSelection) .onChange(of: chartSelection, checkSelection) For testing purposes, I have removed all of the modifiers and only had a simple SectorMark in the Chart, however, that was still crashing. Does anyone know why this is happening?
1
0
54
1w