When building in Xcode on MacOS Tahoe, it seems it is no longer possible to dynamically specify a "small" size toolbar for NSToolbar/NSToolbarItem. It works in MacOS code compiled and linked on earlier systems.
I don't want to use "SFSymbol", or "templates". I have over 60 custom-made .png toolbars, in individual Image Set files, at the previous requisite sizes of 24x24 / 48x48, and 32x32 / 64x64.
Sure -- I can configure an NSToolbar with whatever size .png assets I want. I just can't dynamically switch between the two groups of sizes.
According to the Apple Coding Assistant, the only solution is to change the image names of each of the NSToolbarItems at runtime.
OK -- but even when attempting that, the NSToolbarItems refuse to take on their smaller size...
...unless: they are attached to a custom view NSToolbarItem with an NSButton of style "Bevel". I have about 10 of those, and YES -- I CAN change those to a "small" size. Is this REALLY what I'm forced to do?!
The Apple Coding Assistant just runs me around in circles, making coding suggestions that include properties that don't exists.
I've gone around and around on these issues for over a week -- it can't be this hard, right? Is there no way to make multiple NSToolbar objects, one for "large" and one for "small"?
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
I have the following snippet (but you can see my entire code in GitHub, if you want):
LazyVGrid(columns: columns) {
ForEach(books) { book in
BookView(book: book)
.draggable(Book.BookTransferable(persistanceIdentifier: book.id))
}
}
and BookView is:
VStack {
Image(nsImage: book.image)
.resizable()
.frame(width: 150, height: 200)
.scaledToFill()
Text(book.title)
.lineLimit(1)
.font(.headline)
HStack {
ForEach(book.tags.sorted(), id: \.self) { tag in
TagView(tag: tag, showText: false)
}
}
}
.padding()
This will render each BookView on a different base-line because of the fact that the Text view sometimes takes 1, 2 or even 3 lines (as shown).
How can I have all BookViews alligned at a common base-line (as it would if Text would only take one line, for example)?
I noticing that Monterey defaults to the NSWindowToolbarStyleAutomatic / NSWindowToolbarStyleUnified toolbar style, which suppresses the "use Small Size" menu item and customization checkbox.
So I've set the window to use NSWindowToolbarStyleExpanded. However, the toolbar will no longer change to a smaller icon size, as it did in MacOS 10.14, 10.15, and 11.0.
I've tried to set the toolbar item sizing to "Automatic" for all of our toolbar icons, but that results in bad positioning in both Regular and Small Size mode -- the height is way too big.
The native size of the icon .png files are 128 x 128. What's odd is that if I resize the window with the toolbar to be wider, the NSToolbarItems in the overflow area will be displayed in the toolbar are 128 x 128, where the rest of the toolbar icons get displayed as a 32 x 32 icon.
The only way to get it to layout remotely correct is to make the NSToolbarItem to have an explicit minimum size of 24 x 24 and maximum size of 32 x 32. And that USED to allow "small size", but on Monterey, it no longer does.
Anyone had any success with small size icons on Monterey?
Hello,
I am developing a macOS app using AudioToolbox's MusicSequence and MusicPlayer APIs to play Standard MIDI Files.
The MIDI playback works correctly and I can hear sound from the external MIDI device. However, the user callback registered via MusicSequenceSetUserCallback is never invoked during playback.
Details:
Callback registration returns no error.
MusicPlayer is properly started and prerolled.
The callback is defined as a global function with the correct @convention(c) signature.
I have tried commenting out MusicTrackSetDestMIDIEndpoint to avoid known callback suppression issues.
The clientData pointer is passed and correctly unwrapped in the callback.
Minimal reproducible example shows the same behavior.
Environment:
macOS version: [Tahoe 26.2]
Xcode version: [26.2]
Is it expected that MusicSequenceSetUserCallback callbacks may not be called in some cases?
Are there additional steps or configurations required to ensure the callback is triggered during MIDI playback?
Thank you for any advice or pointers.
Execute playTest() in the viewDidLoad() method of the ViewController.
extension ViewController {
private func playTest() {
NewMusicSequence(&sequence)
if let midiFileURL = Bundle.main.url(forResource: "etude", withExtension: "mid") {
MusicSequenceFileLoad(sequence!, midiFileURL as CFURL, .midiType,MusicSequenceLoadFlags())
NewMusicPlayer(&player)
MusicPlayerSetSequence(player!, sequence!)
MusicPlayerPreroll(player!)
let status = MusicSequenceSetUserCallback(sequence!, musicSequenceUserCallback, Unmanaged.passUnretained(self).toOpaque())
if status == noErr {
print("Callback registered successfully")
} else {
print("Callback registration failed: \(status)")
}
MusicPlayerStart(player!)
} else {
print("MIDI File Not Found")
}
}
}
The callback function was generated by Xcode and defined outside the ViewController.
func musicSequenceUserCallback(
clientData: UnsafeMutableRawPointer?,
sequence: MusicSequence,
track: MusicTrack,
eventTime: MusicTimeStamp,
eventData: UnsafePointer<MusicEventUserData>,
startSliceBeat: MusicTimeStamp,
endSliceBeat: MusicTimeStamp
) {
print("User callback fired at eventTime: \(eventTime)")
if let clientData = clientData {
let controller = Unmanaged<ViewController>.fromOpaque(clientData).takeUnretainedValue()
// Example usage to prove round-trip works (avoid strong side effects in callback)
_ = controller.view // touch to silence unused warning if needed
print("Callback has access to ViewController: \(controller)")
} else {
print("clientData was nil")
}
}
In this app I use tooltips extensively.
They work perfectly well, except in a popover where they may appear or not (just some flash and immediately disappear).
In the popover there are 12 colour buttons, each with its own tracking area and 3 control buttons, with their tracking areas.
Here when it works, hovering over "C" button or "Annuler" button:
But then, when I move to another colour button, a few 2 or 3 may work, but most don't display their tooltip at all.
I know that the tooltip is set because I replicate the message in a help line at the bottom of the screen and this line always update:
Let messageForColor = "Choisir la couleur…"
if button.isEnabled { // show tooltip
button.toolTip = messageForColor
} else {
button.toolTip = nil
}
if button.isEnabled { // Shows helpline at the bottom of screen
button.helpMessage = messageForColor
}
Maybe it comes from some useDefault (I modified NSInitialTool TipDelay and I'm not sure I have reset to the default value)
I noted that if I wait for 10 seconds or so (keeping the popover opened), everything seems to work properly again. Just as if there was some lengthy initialisation going on.
So questions:
Is there a known issue of Tooltips in a popover ?
Are there other parameters to set in userDefaults to avoid immediate disparition of the tooltip in popover ?
How to reset the factory setting for the UserDefaults in the app ?
I’m seeing a camera/capture routing issue on visionOS when multiple WindowGroups are open at the same time.
I have a SwiftUI view that starts an AVCaptureSession on onAppear and stops it on onDisappear. The camera feed is displayed in a subview that only exists inside one window.
However, when I open additional windows (other WindowGroups) in the same app, the camera perspective/route changes unexpectedly — it looks like the capture is being re-associated with a different scene/window, even though the camera view never moved and no other view starts capture.
Expected behavior
Opening additional windows should not affect the active capture session or camera routing for the existing camera view. The camera feed should remain stable and tied to the window hosting.
Actual behavior
When multiple windows are open, the camera feed “switches perspective” / appears to re-route, as if the system changes which scene is considered active for capture. This happens without any explicit code calling startSession() again and without the camera view being present in the other windows.
Additional context
This app is running in an unbounded scene and uses Unity PolySpatial.
In the iOS 13 world, I had code like this:
class SceneDelegate: UIResponder, UIWindowSceneDelegate {
		func windowScene(_ windowScene: UIWindowScene, userDidAcceptCloudKitShareWith cloudKitShareMetadata: CKShare.Metadata) {
				// do stuff with the metadata, eventually call CKAcceptSharesOperation
		}
}
I am migrating my app to the new SwiftUI app lifecycle, and can’t figure out where to put this method. It used to live in AppDelegate pre-iOS13, and I tried going back to that, but the AppDelegate version never gets called.
There doesn’t seem to be a SceneDelegateAdaptor akin to UIApplicationDelegateAdaptor available, which would provide a bridge to the old code.
So, I’m lost. How do I accept CloudKit shares with SwiftUI app lifecycle? 🙈
Has anyone been able to create a Control Center widget that opens a snippet view? There are stock Control Center widgets that do this, but I haven't been able to get it to work.
Here's what I tried:
struct SnippetButton: ControlWidget {
var body: some ControlWidgetConfiguration {
StaticControlConfiguration(
kind: "xxx.xxx.snippetWidget"
) {
ControlWidgetButton(action: SnippetIntent()) {
Label("Show Snippet", systemImage: "map.fill")
}
}
.displayName(LocalizedStringResource("Show Snippet"))
.description("Show a snippet.")
}
}
struct SnippetIntent: ControlConfigurationIntent {
static var title: LocalizedStringResource = "Show a snippet"
static var description = IntentDescription("Show a snippet with some text.")
@MainActor
func perform() async throws -> some IntentResult & ProvidesDialog & ShowsSnippetView {
return .result(dialog: IntentDialog("Hello!"), view: SnippetView())
}
}
struct SnippetView: View {
var body: some View {
Text("Hello!")
}
}
Hi, I have an issue with applying the .glassProminent modifier to a button placed in the leading section the nav bar that triggers a push navigation to another screen in iOS 26.
I have made a simple sample project to verify it happens there too, and I'm getting the same behaviour where the prominent button "flashes" with a darker background and disappears.
The HIG does mention not tinting or adding custom backgrounds to tool bar items in iOS 26, so I'm unsure if this is a bug in iOS 26 or the unexpected behaviour they refer to when adding custom tint/backgrounds.
Below is the simplified sample app code:
var body: some View {
NavigationStack {
VStack {
Text("Main Screen")
.font(.largeTitle)
}
.navigationTitle("Home")
.navigationBarTitleDisplayMode(.inline)
.toolbar {
ToolbarItem(placement: .navigationBarLeading) {
NavigationLink(destination: SecondScreen()) {
Text("Push Nav")
}
.buttonStyle(.glassProminent)
}
}
}
}
}
struct SecondScreen: View {
var body: some View {
VStack {
Text("Second Screen")
.font(.largeTitle)
}
.navigationTitle("Settings")
.navigationBarTitleDisplayMode(.inline)
}
}
Topic:
UI Frameworks
SubTopic:
SwiftUI
This is a very basic macOS Finder-style test app using AppKit. I am experiencing a "jump" in the vertical scroll position of my NSTableView (inside an NSScrollView) specifically when the window is resized horizontally. This happens when columns are visually added or removed.
Framework: AppKit (Cocoa)
Xcode/macOS: 26.2
Code: https://github.com/MorusPatre/Binder/blob/main/ContentView%20-%20Scroll%20Jump%20during%20Resize.swift
I have a UIHostingController on which I have set:
hostingController.sizingOptions = [.intrinsicContentSize]
The size of my SwiftUI content changes with animation (I update a @Published property on an ObservableObject inside a withAnimation block). However, I notice that my hostingController.view just jumps to the new frame without animating the change.
Question: how can I animate the frame changes in UIHostingController that are caused by sizingOptions = [.intrinsicContentSize]
I run into a layout problem where I cannot center an image inside ScrollView which is also inside Navigation Controller. The problem is surely the fact that there is a navigation bar because using this view without NavigationContoller works fine and the image is centered but I don’t know how to account for the space that navigation bar takes up.
Here is the code:
import UIKit
class PhotoViewController: UIViewController {
var photoName: String
private lazy var photoView = {
let image = UIImageView()
image.translatesAutoresizingMaskIntoConstraints = false
image.contentMode = .scaleAspectFit
image.clipsToBounds = true
return image
}()
var photoViewBottomConstraint: NSLayoutConstraint?
var photoViewLeadingConstraint: NSLayoutConstraint?
var photoViewTopConstraint: NSLayoutConstraint?
var photoViewTrailingConstraint: NSLayoutConstraint?
private lazy var scrollView = {
let sv = UIScrollView()
sv.translatesAutoresizingMaskIntoConstraints = false
return sv
}()
override func viewDidLoad() {
super.viewDidLoad()
setupUI()
}
override func viewWillLayoutSubviews() {
super.viewWillLayoutSubviews()
updateMinZoomScaleForSize(view.bounds.size)
}
func updateMinZoomScaleForSize(_ size: CGSize) {
let widthScale = size.width / photoView.bounds.width
let heightScale = size.height / photoView.bounds.height
let minScale = min(widthScale, heightScale)
scrollView.minimumZoomScale = minScale
scrollView.zoomScale = minScale
}
func setupUI() {
photoView.image = UIImage(named: photoName)
scrollView.delegate = self
view.addSubview(scrollView)
scrollView.addSubview(photoView)
setupConstraints()
}
func setupConstraints() {
NSLayoutConstraint.activate([
scrollView.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor),
scrollView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor),
scrollView.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor),
scrollView.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor)
])
photoViewLeadingConstraint = NSLayoutConstraint(
item: photoView,
attribute: .leading,
relatedBy: .equal,
toItem: scrollView,
attribute: .leading,
multiplier: 1,
constant: 0
)
photoViewTopConstraint = NSLayoutConstraint(
item: photoView,
attribute: .top,
relatedBy: .equal,
toItem: scrollView,
attribute: .top,
multiplier: 1,
constant: 0
)
photoViewTrailingConstraint = NSLayoutConstraint(
item: photoView,
attribute: .trailing,
relatedBy: .equal,
toItem: scrollView,
attribute: .trailing,
multiplier: 1,
constant: 0
)
photoViewBottomConstraint = NSLayoutConstraint(
item: photoView,
attribute: .bottom,
relatedBy: .equal,
toItem: scrollView,
attribute: .bottom,
multiplier: 1,
constant: 0
)
photoViewLeadingConstraint?.isActive = true
photoViewTopConstraint?.isActive = true
photoViewTrailingConstraint?.isActive = true
photoViewBottomConstraint?.isActive = true
}
init(photoName: String) {
self.photoName = photoName
super.init(nibName: nil, bundle: nil)
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
extension PhotoViewController: UIScrollViewDelegate {
func viewForZooming(in scrollView: UIScrollView) -> UIView? {
photoView
}
func scrollViewDidZoom(_ scrollView: UIScrollView) {
updateConstraintsForSize(view.bounds.size)
}
func updateConstraintsForSize(_ size: CGSize) {
let yOffset = max(0, (size.height - photoView.frame.height) / 2)
photoViewTopConstraint?.constant = yOffset
photoViewBottomConstraint?.constant = yOffset
let xOffset = max(0, (size.width - photoView.frame.width) / 2)
photoViewLeadingConstraint?.constant = xOffset
photoViewTrailingConstraint?.constant = xOffset
view.layoutIfNeeded()
}
}
My app has a collection of Cell Views. some of the views' model objects include a Player, and others do not.
I want to use drag and drop to move a player from one cell to another. I only want cells that contain a player to be valid drag sources. All cells will be valid drop destinations.
When I uncomment the .disabled line both drag and drop become disabled.
Is it possible to keep a view enabled as a dropDestination but disabled as a draggable source?
VStack {
Image("playerJersey_red")
if let player = content.player {
Text(player.name)
}
}
.draggable(content)
// .disabled(content.player == nil)
.dropDestination(for: CellContent.self) { items, location in
One thing I tried was to wrap everything in a ZStack and put a rectangle with .opacity(0.02) above the Image/Text VStack. I then left draggable modifying my VStack and moved dropDestination to the clear rectangle. This didn't work as I wasn't able to initiate a drag when tapping on the rectangle.
Any other ideas or suggestions?
thanks
Hello,
We are seeing an intermittent crash when initializing a base UITableView with Apple's [initWithFrame:style:] initializer.
Crash stack:
Role: Foreground
OS Version: iOS 26.1
Exception Type: EXC_BREAKPOINT
Exception Subtype: KERN_INVALID_ADDRESS
EXC_BREAKPOINT:
0 libswiftCore.dylib +0x1358c0 _assertionFailure(_:_:file:line:flags:)
1 UIKitCore +0x1fdca0 0x188c26ca0 (0x188c26b20 + 384)
2 UIKitCore +0x1ffa60 0x188c28a60 (0x188c2890c + 340)
3 UIKitCore +0x2012d0 0x188c2a2d0 (0x188c2a1ec + 228)
4 UIKitCore +0x200f20 0x188c29f20 (0x188c29cac + 628)
5 UIKitCore +0x200428 0x188c29428 (0x188c29384 + 164)
6 UIKitCore +0x18af7f4 -[UITableMetricsAdapter _updateSharedSectionMetricsForListGeometry:]
7 UIKitCore +0x201da8 -[UITableMetricsAdapter tableBackgroundColor]
8 UIKitCore +0x1643a44 ___39-[UITableView _applyAppearanceDefaults]_block_invoke
9 UIKitCore +0x196f3d0 +[UIView _performSystemAppearanceModifications:]
10 UIKitCore +0x1643978 -[UITableView _applyAppearanceDefaults]
11 UIKitCore +0x202854 -[UITableView _setupTableViewCommon]
12 UIKitCore +0x1643760 -[UITableView initWithFrame:style:]
13 Application +0x30b6a40 closure #1 in variable initialization expression of MyAppClass.tableView
14 Application +0x30b6ef0 MyAppClass.init(frame:)
Has anyone else seen something like this?
Any insights or advice is much appreciated, thank you!
Hey all,
I found a weird behaviour with the searchable component. I created a custom bottom nav bar (because I have custom design in my app) to switch between screens.
On one screen I display a List component with the searchable component. Whenever I enter the search screen the first time, the searchable component is displayed at the bottom.
This is wrong. It should be displayed at the top under the navigationTitle. When I enter the screen a second time, everything is correct.
This behaviour can be reproduced on all iOS 26 versions on the simulator and on a physical device with debug and release build.
On iOS 18 everything works fine.
Steps to reproduce:
Cold start of the app
Click on Search TabBarIcon (searchable wrong location)
Click on Home TabBarIcon
Click on Search TabBarIcon (searchable correct location)
Simple code example:
import SwiftUI
struct ContentView: View {
@State var selectedTab: Page = Page.main
var body: some View {
NavigationStack {
ZStack {
VStack {
switch selectedTab {
case .main:
MainView()
case .search:
SearchView()
}
}
VStack {
Spacer()
VStack(spacing: 0) {
HStack(spacing: 0) {
TabBarIcon(iconName: "house", selected: selectedTab == .main, displayName: "Home")
.onTapGesture {
selectedTab = .main
}
TabBarIcon(iconName: "magnifyingglass", selected: selectedTab == .search, displayName: "Search")
.onTapGesture {
selectedTab = .search
}
}
.frame(maxWidth: .infinity)
.frame(height: 55)
.background(Color.gray)
}
.ignoresSafeArea(.all, edges: .bottom)
}
}
}
}
}
struct TabBarIcon: View {
let iconName: String
let selected: Bool
let displayName: String
var body: some View {
ZStack {
VStack {
Image(systemName: iconName)
.resizable()
.renderingMode(.template)
.aspectRatio(contentMode: .fit)
.foregroundColor(Color.black)
.frame(width: 22, height: 22)
Text(displayName)
.font(Font.system(size: 10))
}
}
.frame(maxWidth: .infinity)
}
}
enum Page {
case main
case search
}
struct MainView: View {
var body: some View {
VStack {
Image(systemName: "globe")
.imageScale(.large)
.foregroundStyle(.tint)
Text("Hello, world!")
}
.padding()
.navigationTitle("Home")
}
}
struct SearchView: View {
@State private var searchText = ""
let items = [
"Apple",
"Banana",
"Pear",
"Strawberry",
"Orange",
"Peach",
"Grape",
"Mango"
]
var filteredItems: [String] {
if searchText.isEmpty {
return items
} else {
return items.filter {
$0.localizedCaseInsensitiveContains(searchText)
}
}
}
var body: some View {
List(filteredItems, id: \.self) { item in
Text(item)
}
.navigationTitle("Fruits")
.searchable(text: $searchText, placement: .navigationBarDrawer(displayMode: .always), prompt: "Search")
}
}
Context:
I am building a macOS file (currently image only) browser using SwiftUI. The core view is a ScrollView containing a LazyVGrid. The layout is dynamic: as the window resizes, I calculate the optimal number of columns and spacing using a GeometryReader.
The Issue:
While scrolling is pretty smooth (thanks to custom image caching and prefetching), window resizing is significantly laggy. After having scrolled the UI stutters and drops frames heavily while dragging the window edge.
The Code:
https://github.com/MorusPatre/Binder
I am adopting some of the new glass UI, but having to duplicate a lot of code to maintain support for previous UI systems in macOS. An example:
if #available(macOS 26.0, *) {
VStack {
/*some 40+ lines of code clipped here for brevity*/
}
.cueButtons()
.cueStyleGlass()
} else {
VStack {
/*identical 40+ lines of code clipped here for brevity*/
}
.cueButtons()
.cueStyle()
}
If I try to use conditional modifiers as indicated here:
extension View {
func cueStyle(font: Font = .system(size: 45)) -> some View {
if #available(macOS 26.0, *) {
modifier(GlassCueStyle(font: font))
} else {
modifier(CueStyle(font: font))
}
}
}
I get this error:
Conflicting arguments to generic parameter 'τ_1_0' ('ModifiedContent<Self, GlassCueStyle>' vs. 'ModifiedContent<Self, CueStyle>')
Is there a better way to do this?
There is a problem with the launchscreen of my application on iPadOS 26.
After release of the windowed mode feature the launchscreen of my fullscreen landscape-only application is being cropped and doesn't stretch to screen's size when the device is in the portrait mode.
How can I fix this?
Topic:
UI Frameworks
SubTopic:
General
I need to create a Mac application using Objective-C. The application has to use PHPickerViewController to provide user a familiar interface to pick photos.
Here is the Objective-C code that used to present the photo picker.
//ViewController.h
#import <Cocoa/Cocoa.h>
#import <PhotosUI/PhotosUI.h>
@interface ViewController : NSViewController<PHPickerViewControllerDelegate>
@property (nonatomic, weak) IBOutlet NSImageView *myImageView;
@end
// ViewController.m
@implementation ViewController
PHPickerViewController* pickerViewController = nil;
- (void)pickPhotos {
PHPickerConfiguration *config = [[PHPickerConfiguration alloc] init];
config.selectionLimit = 0; // Allow multiple selections
config.filter = [PHPickerFilter imagesFilter]; // Filter for images
pickerViewController = [[PHPickerViewController alloc] initWithConfiguration:config];
pickerViewController.preferredContentSize = NSMakeSize(800, 600);
pickerViewController.delegate = self; // Set the delegate to handle selection
[self presentViewControllerAsModalWindow:pickerViewController];
- (IBAction)clicked:(id)sender {
NSLog(@"Button Clicked");
[self pickPhotos];
}
- (void)picker:(PHPickerViewController *)picker didFinishPicking:(NSArray<PHPickerResult *> *)results {
if (pickerViewController) {
[picker dismissViewController:pickerViewController];
}
}
@end
Can you please guide me to show the photo picker to a bigger size?
Topic:
UI Frameworks
SubTopic:
AppKit
Is there any way to prevent the keyboard from bouncing when changing the focus state in onSubmit? Or is it not recommended to change focus in onSubmit?
The following view is setup so that pressing return on the keyboard should cause focus to move between the TextFields.
struct TextFieldFocusState: View {
enum Field {
case field1
case field2
}
@FocusState var focusedField: Field?
var body: some View {
Form {
TextField("Field 1", text: .constant(""))
.focused($focusedField, equals: .field1)
.onSubmit { focusedField = .field2 }
TextField("Field 2", text: .constant(""))
.focused($focusedField, equals: .field2)
.onSubmit { focusedField = .field1 }
}
}
}
I would expect that when pressing return, the keyboard would say on screen.
What actually happens is the keyboard appears to bounce when the return key is pressed (first half of gif). I assume this is because onSubmit starts dismissing the keyboard then setting the focus state causes the keyboard to be presented again.
The issue doesn't occur when tapping directly on the text fields to change focus (second half of gif).