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

Created

Multiline Text not possible in accessoryRectangular widget on lock screen
Filed as FB20766506 I have a very simple use case for a rectangular widget on the iPhone lock screen: One Text element which should fill as much space as possible. However, it only ever does 2 per default and then eclipses the rest of the string. Three separate Text elements work fine, so does a fixedSize modifier hack (with that even four lines are possible!). Am I completely misunderstanding something or why is this not possible per default? Other apps' widgets like Health do it as well. My attempt (background added for emphasis) Health app widget var body: some View { VStack(alignment: .leading) { /// This should span three lines, but only spans 2 which eclipsed text. Text("This is a very long text which should span multiple lines.") // .fixedSize(horizontal: false, vertical: true) /// Using this fixes it as well, but that does not seem like a good default solution. /// Three separate `Text` elements work fine. // Text("This is a very long") // Text("text which should") // Text("span multiple lines.") } .frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .leading) .background(Color.black) /// Added for emphasis of the widget frame }
2
0
94
3w
Migrating a Single-View Objective-C Application to the UIKit Scene-Based Life Cycle
Hello! I've been using Objective-C to write a single-view application and have been using AppDelegate for my window setup. However, with the next release of iOS, I need to adopt SceneDelegate into my app for it to work. I'm having trouble getting my main ViewController to show up when the app starts. It just shows up as a black screen. I built this app entirely programmatically. When I go into my info.plist file, I have everything but the Storyboard setup since, obviously, I don't have one. I've left my code below. Thank you! My current AppDelegate: #import "ViewController.h" @interface AppDelegate () @end @implementation AppDelegate #pragma mark - UISceneSession Configuration - (UISceneConfiguration *)application:(UIApplication *)application configurationForConnectingSceneSession:(UISceneSession *)connectingSceneSession options:(UISceneConnectionOptions *)options { // Create the configuration object return [[UISceneConfiguration alloc] initWithName: @"Default" sessionRole: connectingSceneSession.role]; } #pragma mark - Application Configuration - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { return YES; } - (void) dealloc { [super dealloc]; } @end My Current SceneDelegate: #import "SceneDelegate.h" #import "ViewController.h" @interface SceneDelegate () @end @implementation SceneDelegate - (void)scene:(UIScene *)scene willConnectToSession:(UISceneSession *)session options:(UISceneConnectionOptions *)connectionOptions { // Ensure we have a UIWindowScene if (![scene isKindOfClass:[UIWindowScene class]]) { return; } UIWindowScene *windowScene = (UIWindowScene *)scene; // Create and attach the window to the provided windowScene self.window = [[UIWindow alloc] initWithWindowScene:windowScene]; // Set up the root view controller ViewController *homeViewController = [[[ViewController alloc] init] autorelease]; UINavigationController *navigationController = [[[UINavigationController alloc] initWithRootViewController: homeViewController] autorelease]; // Present the window self.window.rootViewController = navigationController; [self.window makeKeyAndVisible]; } @end
Topic: UI Frameworks SubTopic: UIKit Tags:
2
0
182
3w
Incorrect padding in TextField with .rightToLeft layout direction
When a TextField is set to a rightToLeft layout, it gets strange and unnecessary padding on the left side. This pushes the text away from the edge. This issue doesn't occur in the leftToRight layout, where the text aligns correctly. Does anyone know how to get rid of this extra padding? Environment: Xcode version: 26.0.1 Device: iPhone 13 iOS version: 26.0 Code: struct ContentView: View { @State var textInput: String = "" var body: some View { VStack { Text("rightToLeft") TextField("placeholder", text: $textInput) .background(Color.red) .environment(\.layoutDirection, .rightToLeft) Text("leftToRight") TextField("placeholder", text: $textInput) .background(Color.red) .environment(\.layoutDirection, .leftToRight) } .padding() } }
1
1
182
3w
Bottom toolbar Button truncated on Mac Catalyst 26
On Mac Catalyst 26, a Button bar item in a bottom toolbar look squished. This happens only when the "Mac Catalyst Interface" option is set to "Optimize for Mac". When it is set to "Scale to match iPad", the buttons look fine. For example, in the screenshots below, the text button should say "Press Me", instead of "…" A simple reproducible snippet and a screenshot below. The toolbar button comparison between "Scale to match iPad" and "Optimize for Mac" are shown. Optimize for Mac Scale to match iPad import SwiftUI struct ContentView: View { @State private var selectedItem: String? = "Item 1" let items = ["Item 1", "Item 2"] var body: some View { NavigationSplitView { List(items, id: \.self, selection: $selectedItem) { item in Text(item) } .navigationTitle("Items") } detail: { if let selectedItem = selectedItem { Text("Detail view for \(selectedItem)") .toolbar { ToolbarItemGroup(placement: .bottomBar) { Text("Hello world") Spacer() Button("Press Me") { } Spacer() Button { } label: { Image(systemName: "plus") .imageScale(.large) } } } } else { Text("Select an item") } } } }
0
1
137
3w
popoverTips don't display for toolbar menu buttons in iOS 26.1
[Also submitted as FB20756013] A popoverTip does not display for toolbar menu buttons in iOS 26.1 (23B5073a). The same code displays tips correctly in iOS 18.6. The issue occurs both in the simulator and on a physical device. Repro Steps Build and run the Sample Code below on iOS 26.1. Observe that the popoverTip does not display. Repeat on iOS 18.6 to confirm expected behavior. Expected popoverTips should appear when attached to a toolbar menu button, as they do in iOS 18.6. Actual No tip is displayed on iOS 26.1. System Info macOS 15.7.1 (24G231) Xcode 26.1 beta 3 (17B5045g) iOS 26.1 (23B5073a) Screenshot Screenshot showing two simulators side by side—iOS 18.6 on the left (tip displayed) and iOS 26.1 on the right (no tip displayed). Sample code import SwiftUI import TipKit struct PopoverTip: Tip { var title: Text { Text("Menu Tip") } var message: Text? { Text("This tip displays on iOS 18.6, but NOT on iOS 26.1.") } } struct ContentView: View { var tip = PopoverTip() var body: some View { NavigationStack { Text("`popoverTip` doesn't display on iOS 26.1 but does in iOS 18.6") .padding() .toolbar { ToolbarItem(placement: .topBarTrailing) { Menu { Button("Dismiss", role: .cancel) { } Button("Do Nothing") { } } label: { Label("More", systemImage: "ellipsis") } .popoverTip(tip) } } .navigationTitle("Popover Tip Issue") .navigationBarTitleDisplayMode(.inline) } } }
2
2
103
3w
UICollectionView drop delegate not called with multiple items
I'm working on implementing drag and drop to rearrange items in my UICollectionView. The issue I'm running into is that my drop delegate's collectionView(_, performDropWith:) method isn't getting called when the drag has multiple items. With single item drags, it works fine. What would cause it to break with multiple items? I've replicated it in a basic sample app. Below is the drop delegate. class CollectionDropDelegate: NSObject, UICollectionViewDropDelegate { let controller: MainViewController init(controller: MainViewController) { self.controller = controller } func collectionView(_ collectionView: UICollectionView, canHandle session: any UIDropSession) -> Bool { session.localDragSession != nil } func collectionView(_ collectionView: UICollectionView, dropSessionDidUpdate session: any UIDropSession, withDestinationIndexPath destinationIndexPath: IndexPath?) -> UICollectionViewDropProposal { if session.localDragSession != nil { .init(operation: .move, intent: .insertAtDestinationIndexPath) } else { .init(operation: .cancel) } } func collectionView(_ collectionView: UICollectionView, performDropWith coordinator: any UICollectionViewDropCoordinator) { let destinationPath = coordinator.destinationIndexPath ?? IndexPath(item: 0, section: controller.items.count) for item in coordinator.items { guard let draggedItem = item.dragItem.localObject as? NumberItem, let currentIndex = controller.items.firstIndex(of: draggedItem) else { continue } controller.items.remove(at: currentIndex) controller.items.insert(draggedItem, at: destinationPath.item) coordinator.drop(item.dragItem, toItemAt: destinationPath) collectionView.moveItem(at: IndexPath(item: currentIndex, section: 0), to: destinationPath) } } }
Topic: UI Frameworks SubTopic: UIKit
2
0
80
3w
Navigation bar push animation glitch in iOS 26
At a high level, my app’s view hierarchy is a UISplitViewController, where the secondary column contains a UITabBarController that contains several UINavigationControllers. With this particular setup, I’m noticing every time a view controller is pushed, the navigation bar animation glitches. Notice how the back button and navigation title slightly slide left on each push, before abruptly resetting their positions. This issue only occurs when Liquid Glass is enabled. The issue does not occur if the UIDesignRequiresCompatibility key is added with a value of YES. I assume this is a UIKit bug, so I’ve filed FB20751418. But wondering if anyone is aware of any workarounds in the meantime as this animation glitch is quite distracting.
Topic: UI Frameworks SubTopic: UIKit
2
0
109
3w
Issues with Searchable Modifier Placement and State in TabView on iOS 26
Hi everyone, I'm updating my app to adopt the new search bar design in iOS 26 and I'm running into some UI issues depending on the implementation pattern. I'm using Xcode 26.0.1 and SwiftUI 6. I've tried two main approaches for search, and each has a specific problem related to TabView. Pattern 1: Searchable View Inside a Standard Tab In this pattern, the search bar is specific to one of the main tabs. The Code: struct ContentView: View { var body: some View { TabView { Tab("Main", systemImage: "list.bullet") { MainView() } Tab("View1", systemImage: "gearshape") { Text("View1") } Tab("View2", systemImage: "gearshape") { Text("View2") } } } } struct MainView: View { @State private var searchText = "" var body: some View { NavigationStack { List { Text("Text 1") Text("Text 2") } .searchable(text: $searchText, placement: .toolbar) .navigationTitle("Main") } } } The Problem: When I preview MainView directly, the search bar correctly appears at the bottom, matching the new iOS 26 design. However, when MainView is presented inside the TabView in ContentView, two issues occur: Incorrect Position: The search bar reverts to the old style, appearing at the top of the view, attached to the navigation bar. Initially Hidden: Often, on the first appearance of the view, the search bar is hidden until I actively pull down on the list. It seems like the TabView environment is interfering with the expected placement and initial state of the searchable modifier. Pattern 2: Dedicated Global Search Tab (role: .search) Here, I'm using a dedicated tab for a global search experience, with the searchable modifier on the TabView itself. The Code: struct ContentView: View { @State private var searchText: String = "" var body: some View { TabView { Tab(role: .search) { SearchView() } Tab("Main", systemImage: "list.bullet") { MainView() } Tab("View1", systemImage: "gearshape") { Text("View1") } Tab("View2", systemImage: "gearshape") { Text("View2") } } .searchable(text: $searchText) } } struct MainView: View { var body: some View { NavigationStack { List { Text("Text 1") Text("Text 2") } .navigationTitle("Main") } } } The Problem: The search state is leaking into other tabs in an unexpected way. Steps to Reproduce: Run the app and tap on the "Search" tab. Tap the search bar to activate it and bring up the keyboard. Now, tap on the "Main" tab. Result: The app switches to MainView, but the search bar remains active and focused at the top of the MainView. This is incorrect; the search UI should be dismissed when switching away from the search context. Interestingly, if I tap on "View1" or "View2" (which don't have a NavigationStack), the search bar is correctly dismissed. This suggests the .searchable modifier on the TabView is attaching its UI to the first available NavigationStack it finds in the selected tab. My Questions: For Pattern 1, is there a correct way to ensure the new bottom-placed search bar appears reliably inside a TabView? For Pattern 2, how can I ensure the search state is properly dismissed when navigating away from the search tab, even to a tab that contains a NavigationStack? Is this a potential bug, or am I misusing the APIs for these scenarios? Any guidance or workarounds would be greatly appreciated. Thanks!
1
0
67
3w
crash when call keyboardAppearance of UITextDocumentProxy
In third-party keyboard app, the app is crashed when call [[UIInputViewController textDocumentProxy] keyboardAppearance]. Environment) iOS 26 crash dump call stack Thread 0 Crashed: 0 libobjc.A.dylib 0x0000000198433008 objc_msgSend + 8 1 UIKitCore 0x00000001a1cea570 -[_UITextDocumentInterface _controllerState] + 68 2 UIKitCore 0x00000001a1ceaef0 -[_UITextDocumentInterface documentIdentifier] + 20 3 ThirtPartyKeyboardApp 0x0000000104aad190 -[NKBKeyboardViewController _updateThemeCenterAppearanceModeIfNeeds] + 56 (NKBKeyboardViewController.m:164)
0
0
77
3w
When is the StateObject’s autoclosure actually called?
The signature of the StateObject initializer is init(wrappedValue thunk: @autoclosure @escaping () -> ObjectType). The fact that the autoclosure is marked as escaping intrigues me, because that suggests that it could be called after the init has returned. Why this is interesting is because I have some code where the viewmodel given to the @StateObject depends on an implicitly unwrapped optional type, and I expect the top level initialization of the StateObject to crash because the implicitly unwrapped optional is not ready yet, but to my surprise it did not. My theory is that the autoclosure is being called after the View’s initialization had been called, when the dependency is ready. heres a minimal sample of that. class MyDependency: ObservableObject { @Published var value = "Hello" } class MyViewModel: ObservableObject { let dependency: MyDependency init(dependency: MyDependency = TestApp.dependency) { self.dependency = dependency print("✅ ViewModel initialized with dependency:", dependency.value) } } struct ContentView: View { @StateObject private var viewModel = MyViewModel() // ⚠️ expected crash? var body: some View { Text(viewModel.dependency.value).onAppear { TestApp.dependency = Dependency()// dependency is set here after init has been called } } } @main struct TestApp: App { static var dependency: MyDependency! // not ready yet var body: some Scene { WindowGroup { ContentView() } }```
0
0
99
3w
Old values not cleared when Live Activity updates in CarPlay
I'm updating some of the views for a Live Activity, now that CarPlay can display Live Activities in iOS 26. My Activity is updated only with local updates from the iPhone (no push notifications), displaying a user's blood glucose. The activity updates fine in both CarPlay and in the Apple Watch Smart Stack, but in CarPlay, the previous values are not cleared when the new values are displayed, resulting in superimposed text and making it essentially unreadable. This only happens when the iPhone screen is off. As soon as the phone screen is woken up, even if the phone is not unlocked, the old values disappear and the display looks fine. I can't find anything in the API about clearing a display, so I'm wondering if this is a bug (especially since it clears when waking the phone screen). I'm running iOS 26.0.1 on my test phone. Thanks for any thoughts!
5
0
116
3w
SwiftUI document based app: weird NavBar colors since iOS 26
I have multiple document based SwiftUI apps without any NavigationBar customization. Since upgrading to iOS 26 , when these apps launch, sometimes their navigation bar icons appear grey (as if only the button shadows were showing) and the document title is white, so it’s invisible. One of the apps has an Inspector: here, whenever the Inspector appears, the colors are correct. This behavior has been consistent since the first iOS 26 developer beta and can be reproduced on iOS 26.1 beta 23B5064e. So far I have only managed to reproduce this in light mode.
1
0
105
3w
iOS 26 Keyboard Toolbar with Menu Buttons: Menu appears above hidden toolbar (instead of taking up it's space)
Hi Community! I'm wrangling with this for a few days now and can't find a way to fix it, but I see it working in other apps. I have a regular UIToolbar with buttons, assigning it as inputAccessoryView to a UITextView, so the toolbar appears above the keyboard (I can reproduce this also in SwiftUI). The toolbar contains regular UIBarButtonItems, except one doesn't have an action, it has a UIMenu (using .menu = UIMenu...). In the Apple Notes app, there is also one button that shows a menu like that. When you tap on the button, the toolbar disappears and the menu shows directly above the keyboard. However, in my code it shows above the hidden toolbar, means there is a huge gap between keyboard and menu. It works if I attach the toolbar (in SwiftUI) to the navigation at the top or bottom, just with the keyboard it behaves differently. Here is some sample code for the toolbar: private lazy var accessoryToolbar: UIToolbar = { let toolbar = UIToolbar() let bold = UIBarButtonItem(image: UIImage(systemName: "bold"), style: .plain, target: self, action: #selector(didTapToolbarButton(_:))) let italic = UIBarButtonItem(image: UIImage(systemName: "italic"), style: .plain, target: self, action: #selector(didTapToolbarButton(_:))) let underline = UIBarButtonItem(image: UIImage(systemName: "underline"), style: .plain, target: self, action: #selector(didTapToolbarButton(_:))) let todo = UIBarButtonItem(image: UIImage(systemName: "checklist"), style: .plain, target: self, action: #selector(didTapToolbarButton(_:))) // Make the Bullet button open a menu of list options let bullet = UIBarButtonItem(image: UIImage(systemName: "list.bullet"), style: .plain, target: self, action: nil) let bulletMenu = UIMenu(title: "Insert List", children: [ UIAction(title: "Bulleted List", image: UIImage(systemName: "list.bullet")) { [weak self] _ in self?.handleMenuSelection("Bulleted List") }, UIAction(title: "Numbered List", image: UIImage(systemName: "list.number")) { [weak self] _ in self?.handleMenuSelection("Numbered List") }, ]) bullet.menu = bulletMenu toolbar.items = [bold, italic, underline, todo, bullet] toolbar.sizeToFit() return toolbar }() Somewhere else in the code assign it to the UITextView: // Attach the toolbar above the keyboard textView.inputAccessoryView = accessoryToolbar Toolbar: Menu open: In Apple Notes: I feel I miss something. In Apple notes I can also see a Liquid Glass style gradient between the toolbar and keyboard, dimming the content in this space.
1
0
141
3w
How to prevent VoiceOver from reading text INSIDE an image?
In the example below, VoiceOver (in both iOS 18 and 26) reads the text contained within the image after the .accessibilityLabel, introduced by a “beep.” VoiceOver: Purple rounded square with the word 'Foo' in white letters. Image [beep] foo. I’d like it to only read the accessibility label. As a developer focused on accessibility, I make sure every image already has an appropriate label, so having iOS read the image text is redundant. Sample Code import SwiftUI struct ContentView: View { var body: some View { Image("TextInImage") .resizable() .scaledToFit() .frame(width: 64, height: 64) .accessibilityLabel("Purple rounded square with the word 'Foo' in white letters.") } } Sample Image Drop this image in to Assets.xcassets and confirm it's named TextInImage.
4
0
171
3w
NSScrollView only scrolls vertically for NSTableView after window resize
Hi everyone, I’m looking for help with an issue where using insertRows to add a row to an NSTableView requires resizing the window before I can scroll to the newly added rows that extend beyond the visible area of the NSScrollView. import Cocoa class ViewController: NSViewController { var data = Constants.movies // Table components var titleField = NSTextField() var directorField = NSTextField() var releaseYearField = NSTextField() var addMovieButton = NSButton(title: "Add Movie", image: NSImage(systemSymbolName: "plus", accessibilityDescription: "")!, target: nil, action: #selector(addMovie)) var table = NSTableView() var titleColumn = NSTableColumn(identifier: NSUserInterfaceItemIdentifier(Constants.titleColumnId)) var directorColumn = NSTableColumn(identifier: NSUserInterfaceItemIdentifier(Constants.directorColumnId)) var releaseYearColumn = NSTableColumn(identifier: NSUserInterfaceItemIdentifier(Constants.releaseColumnId)) // Scroll view let scrollView = NSScrollView() override func viewDidLoad() { super.viewDidLoad() // Do any additional setup after loading the view. view.wantsLayer = true view.layer?.backgroundColor = NSColor.black.cgColor configure() } private func configure() { titleField.translatesAutoresizingMaskIntoConstraints = false directorField.translatesAutoresizingMaskIntoConstraints = false releaseYearField.translatesAutoresizingMaskIntoConstraints = false addMovieButton.translatesAutoresizingMaskIntoConstraints = false scrollView.translatesAutoresizingMaskIntoConstraints = false table.translatesAutoresizingMaskIntoConstraints = false titleField.placeholderString = "Movie Title" directorField.placeholderString = "Name of Director" releaseYearField.placeholderString = "Year Released" // Configure table table.addTableColumn(titleColumn) table.addTableColumn(directorColumn) table.addTableColumn(releaseYearColumn) titleColumn.title = "Movie Title" directorColumn.title = "Director" releaseYearColumn.title = "Year Released" table.delegate = self table.dataSource = self table.focusRingType = .none // Configure scroll view scrollView.documentView = table scrollView.hasVerticalScroller = true scrollView.hasHorizontalScroller = false scrollView.autohidesScrollers = true // Add views to the hierarchy view.addSubview(titleField) view.addSubview(directorField) view.addSubview(releaseYearField) view.addSubview(addMovieButton) view.addSubview(scrollView) // view.addSubview(table) NSLayoutConstraint.activate([ titleField.widthAnchor.constraint(equalToConstant: 150), directorField.widthAnchor.constraint(equalToConstant: 150), releaseYearField.widthAnchor.constraint(equalToConstant: 150), addMovieButton.widthAnchor.constraint(equalToConstant: 100), titleField.topAnchor.constraint(equalTo: view.topAnchor, constant: 20), directorField.topAnchor.constraint(equalTo: view.topAnchor, constant: 20), releaseYearField.topAnchor.constraint(equalTo: view.topAnchor, constant: 20), addMovieButton.topAnchor.constraint(equalTo: view.topAnchor, constant: 20), directorField.trailingAnchor.constraint(equalTo: view.centerXAnchor, constant: -10), releaseYearField.leadingAnchor.constraint(equalTo: view.centerXAnchor, constant: 10), titleField.trailingAnchor.constraint(equalTo: directorField.leadingAnchor, constant: -20), addMovieButton.leadingAnchor.constraint(equalTo: releaseYearField.trailingAnchor, constant: 20), scrollView.topAnchor.constraint(equalTo: titleField.bottomAnchor, constant: 20), scrollView.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 20), scrollView.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -20), scrollView.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: -20), // table.widthAnchor.constraint(equalTo: scrollView.contentView.widthAnchor), // table.heightAnchor.constraint(equalTo: scrollView.contentView.heightAnchor) ]) } @objc private func addMovie() { let title = titleField.stringValue let director = directorField.stringValue guard let year = Int(releaseYearField.stringValue) else { return } let movie = Movie(title: title, director: director, releaseYear: year) data.append(movie) // Approach 1 // table.reloadData() // Approach 2 let newRow = data.count - 1 table.insertRows(at: IndexSet(integer: newRow), withAnimation: .slideDown) } Using table.reloadData works fine and I can scroll to the new rows as I add them, but it doesn't have the smooth animation I want to achieve. What is the best practice and correct way for using table.insertRows to avoid this issue? Note: I am using programmatic constraints only.
1
0
62
3w
Exporting and restoring AttributedString in rich TextEditor (iOS 26)
I am working with the rich TextEditor introduced in iOS 26, but I am having trouble preserving AttributedString formatting when converting to/from RTF. Here is my exporting logic in my view model (AttributedString to RTF) let nsAttrStr = NSAttributedString(self.text) // text is an AttributedString (bound to the TextEditor input) let range = NSRange(location: 0, length: nsAttrStr.length) let options: [NSAttributedString.DocumentAttributeKey: Any] = [ .documentType: NSAttributedString.DocumentType.rtf ] guard let data = try? nsAttrStr.data(from: range, documentAttributes: options) else { return nil } let rtfBase64 = data.base64EncodedString() When I inspect the result, it seems to lose the font, size, boldness, etc which is being correctly rendered in the TextEditor. When I convert back from RTF to an AttributedString, it reverts to the default text formatting applied in the TextEditor. Any ideas what could be going wrong?
1
0
147
3w