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

Too many bugs porting to iOS 26
Has anyone noticed that there are way too many bugs caused by the liquid glass issues? I'm noticing apple adding private layer classes between existing UI views to add glassy effect and no way to disable them. Some of these bugs have no way around without rewriting the code from. For example, search controller doesn't work anymore on iOS 26 but does work on iOS 18. The tab bar controller doesn't show at all on iOS 26 but does on iOS 18. I'm wondering if other people are facing the same issues.
Topic: UI Frameworks SubTopic: General
0
0
363
Dec ’25
iOS 26 + UINavigationBar crash in layoutSubViews - new observation tracking
My #1 crash report since iOS 26 is the following: 1 libobjc.A.dylib objc_exception_throw 2 Foundation -[NSAssertionHandler handleFailureInMethod:object:file:lineNumber:description:] 3 UIKitCore -[UINavigationBar layoutSubviews] 4 UIKitCore UIView._layoutSubviewsWithObservationTracking() 5 UIKitCore @objc UIView._layoutSubviewsWithObservationTracking() Thread 0 9 libobjc.A.dylib objc_exception_throw 10 Foundation -[NSAssertionHandler handleFailureInMethod:object:file:lineNumber:description:] 11 UIKitCore -[UINavigationBar layoutSubviews] 12 UIKitCore UIView._layoutSubviewsWithObservationTracking() 13 UIKitCore @objc UIView._layoutSubviewsWithObservationTracking() I tried many things, without success so far. It seemed related to the new view update with observation tracking: link to documentation Any lead on how I should investigate this? Many thanks in advance!!
Topic: UI Frameworks SubTopic: UIKit Tags:
1
0
407
Dec ’25
Setting `navigationItem.standardAppearance` overrides backButtonImage setting
Hello everybody. I need your help with configuring navigationItem properly. I want to use its appearance properties to configure how the navigation bar looks on per-screen basis without interacting with UINavigationBar directly (the API has been implemented for this specific use case, right?) What I'm confused about is that setting any appearance property resets back button image to the default chevron. What I do now: Inside my app delegate let navigationBarAppearance = UINavigationBar.appearance() navigationBarAppearance.backIndicatorImage = UIImage() navigationBarAppearance.backIndicatorTransitionMaskImage = UIImage() I do this to hide the default chevron to customize back button appearance on per-view-controller basis Then in my presenting view controller: override func viewDidLoad() { super.viewDidLoad() navigationItem.title = "Root" navigationItem.backBarButtonItem = UIBarButtonItem( title: nil, image: nil, primaryAction: UIAction( title: "", image: UIImage(systemName: "square.and.arrow.up"), identifier: nil, discoverabilityTitle: nil, attributes: [], state: .on, handler: { [weak self] _ in self?.navigationController?.popViewController(animated: true) } ), menu: nil ) let appearance = UINavigationBarAppearance() appearance.configureWithTransparentBackground() appearance.backgroundColor = UIColor.red appearance.titleTextAttributes = [ .foregroundColor: UIColor.purple ] appearance.largeTitleTextAttributes = [ .foregroundColor: UIColor.purple ] navigationItem.standardAppearance = appearance navigationItem.compactAppearance = appearance navigationItem.scrollEdgeAppearance = appearance navigationItem.compactScrollEdgeAppearance = appearance } The colors are set up as expected, however the default chevron image appears on the next view controller next to square.and.arrow.up. If I don't touch navigation item appearance properties - only square.and.arrow.up is displayed, as I want, but obviously I loose all the customization. Can anyone please explain how to set things up properly? Thanks!
Topic: UI Frameworks SubTopic: UIKit Tags:
0
0
187
Dec ’25
AppIntents default value
Hi, I have created an AppIntent in which there is a parameter called price, I have set the default value as 0. @Parameter(title: "Price", default: 0) var price: Int Problem When the shortcut is run this parameter is skipped Aim I still want to price to be asked however it needs to be pre-filled with 0 Question What should I do that the shortcut can still ask the price but be pre-filled with 0?
0
0
84
Dec ’25
AppIntents
Overview I have a custom type Statistics that has 3 properties inside it I am trying to return this as part of the AppIntent's perforrm method struct Statistics { var countA: Int var countB: Int var countC: Int } I would like to implement the AppIntent to return Statistics as follows: func perform() async throws -> some IntentResult & ReturnsValue<Statistics> { ... ... } Problem It doesn't make much sense to make Statistics as an AppEntity as this is only computed as a result. Statistics doesn't exist as a persisted entity in the app. Questions How can I implement Statistics? Does it have to be AppEntity (I am trying to avoid this)? (defaultQuery would never be used.) What is the correct way tackle this?
2
0
257
Dec ’25
Why does NSEvent.addGlobalMonitorForEvents still work in a Sandboxed macOS app
I am building a macOS utility using SwiftUI and Swift that records and displays keyboard shortcuts (like Cmd+C, Cmd+V) in the UI. To achieve this, I am using NSEvent.addGlobalMonitorForEvents(matching: [.keyDown]). I am aware that global monitoring usually requires the app to be non-sandboxed. However, I am seeing some behavior I don't quite understand during development: I started with a fresh SwiftUI project and disabled the App Sandbox. I requested Accessibility permissions using AXIsProcessTrustedWithOptions, manually enabled it in System Settings, and the global monitor worked perfectly. I then re-enabled the App Sandbox in "Signing & Capabilities." To my surprise, the app still records global events from other applications, even though the Sandbox is now active. Is this expected behavior? Does macOS "remember" the trust because the Bundle ID was previously authorized while non-sandboxed, or is there a specific reason a Sandboxed app can still use addGlobalMonitor if the user has manually granted Accessibility access? My app's core feature is displaying these shortcuts for the user's own reference (productivity tracking). If the user is the one explicitly granting permission via the Accessibility privacy pane, will Apple still reject the app for using global event monitors within a Sandboxed environment? Code snippet of my monitor: // This is still firing even after re-enabling Sandbox eventMonitor = NSEvent.addGlobalMonitorForEvents(matching: [.keyDown]) { event in print("Captured: \(event.charactersIgnoringModifiers ?? "")") } I've tried cleaning the build folder and restarting the app, removing the app from accessibility permission, but the events keep coming through. I want to make sure I'm not relying on a "development glitch" before I commit to the App Store path. Here is the full code anyone can use to try this :- import SwiftUI import Cocoa import Combine struct ShortcutEvent: Identifiable { let id = UUID() let displayString: String let timestamp: Date } class KeyboardManager: ObservableObject { @Published var isCapturing = false @Published var capturedShortcuts: [ShortcutEvent] = [] private var eventMonitor: Any? // 1. Check & Request Permissions func checkAccessibilityPermissions() -> Bool { let options: NSDictionary = [kAXTrustedCheckOptionPrompt.takeUnretainedValue() as String: true] let accessEnabled = AXIsProcessTrustedWithOptions(options) return accessEnabled } // 2. Start Capture func startCapture() { guard checkAccessibilityPermissions() else { print("Permission denied") return } isCapturing = true let mask: NSEvent.EventTypeMask = [.keyDown, .keyUp] eventMonitor = NSEvent.addGlobalMonitorForEvents(matching: mask) { [weak self] event in self?.processEvent(event) } } // 3. Stop Capture func stopCapture() { if let monitor = eventMonitor { NSEvent.removeMonitor(monitor) eventMonitor = nil } isCapturing = false } private func processEvent(_ event: NSEvent) { // Only log keyDown to avoid double-counting the UI display guard event.type == .keyDown else { return } var modifiers: [String] = [] var symbols: [String] = [] // Map symbols for the UI if event.modifierFlags.contains(.command) { modifiers.append("command") symbols.append("⌘") } if event.modifierFlags.contains(.shift) { modifiers.append("shift") symbols.append("⇧") } if event.modifierFlags.contains(.option) { modifiers.append("option") symbols.append("⌥") } if event.modifierFlags.contains(.control) { modifiers.append("control") symbols.append("⌃") } let key = event.charactersIgnoringModifiers?.uppercased() ?? "" // Only display if a modifier is active (to capture "shortcuts" vs regular typing) if !symbols.isEmpty && !key.isEmpty { let shortcutString = "\(symbols.joined(separator: " ")) + \(key)" DispatchQueue.main.async { // Insert at the top so the newest shortcut is visible self.capturedShortcuts.insert(ShortcutEvent(displayString: shortcutString, timestamp: Date()), at: 0) } } } } PS :- I just did another test by creating a fresh new project with the default App Sandbox enabled, and tried and there also it worked!! Can I consider this a go to for MacOs app store than?
1
0
551
Dec ’25
SwiftUI ScrollView blocked when content contains a drag gesture
I am porting my app to SwiftUI and I am hitting a wall when using ScrollView. In my application, I have nested scrollViews to represent a scheduler. outer vertical scroll view inner horizontal scroll view that allows to horizontally scroll multiple columns in the scheduler each column in the inner scroll view is a view that needs to allow for a drag to initiate the creation of a new appointment on macOS, I do a mouse-down drag, so it does not affect the scroll view and works fine on iOS, if I add a drag gesture to the column, it short circuits the scroll view and scrolling becomes disabled. To initiate the drag, there is a long-press, and that gesture is fine, only the subsequent drag gesture is problematic. I have attached URL to a test app. The UI allows you to toggle the drag gesture. Hopefully, someone can help to get it to work since I would eventually like to port the macOS target to Catalyst. Download Test App
Topic: UI Frameworks SubTopic: SwiftUI
2
0
161
Dec ’25
SwiftUI List cell reuse / view lifecycle behavior when scrolling
I’m trying to understand how SwiftUI List handles row lifecycle and reuse during scrolling. I have a list with around 60 card views; on initial load, only about 7 rows are created, but after scrolling to the bottom all rows appear to be created, and when scrolling back to the top I again observe multiple updates and apparent re-creation of rows. I confirmed this behavior using Instruments by profiling my app. Even though each row has a stable identifier, the row views still seem to be destroyed and recreated, which doesn’t resemble UIKit’s cell reuse model. I’d like clarity on how List uses identifiers internally, what actually gets reused versus recreated, and how developers should reason about performance and view lifetime in this case.
0
1
196
Dec ’25
MacCatalyst and the User's Documents Folder
I have a SwiftUI-based universal app which creates a file that it stores in documentsDirectory. On iOS/iPadOS, this file is stored in the application's Documents directory and is accessible via the Files app. On MacCatalyst, this operation does the same thing — it creates the file and stores it in ~/Library/Containers/<app directory>/Data/Documents. However what I want is for the document to be stored in ~/Documents, so that it is easily accessible to the user. How can I do that? I'd like it to occur without (for example) having to show a SaveFile panel...
4
0
514
Dec ’25
App delegate's openURLs: handler not taking .app (application) types any more
So, I was going to make a macOS application that accepts dropped apps. This used to work fine in older macOS versions such as High Sierra. It also works for apps like Script Editor. But I cannot get my own app, made with either Xcode or Script Editor, receive dropped apps any more. Mind you, Finder does accept dropping .app items onto my app, so the CFBundleDocumentTypes are fine. And, as I said, it works in High Sierra. The problem is that some part in AppKit or Core Services filters out apps from the list of dropped URLs before application:openURLs: is invoked. What's up with that, and how do I make this work again? I've tried copying all of Script Editor's Info.plist entries to no avail, so there's something more sinister going on here. Also filed under FB21456137
Topic: UI Frameworks SubTopic: AppKit
1
0
89
Dec ’25
listRowBackground vs swipeActions ios26 compatibility
Hi! On iOS 26, Apple’s Mail app shows an effect where a list row gets rounded corners while you’re swiping (so the row visually “matches” the rounded swipe buttons). In my app I’m using SwiftUI List + .swipeActions. I also need a custom row tint (e.g. subtle red/gray highlight based on state). The problem is: If I apply my tint using .background / .clipShape, it moves with the row content during swipe and looks wrong. If I use .listRowBackground(...), I keep the tint, but I don’t get the same rounded-corners “morphing” effect as in Mail (or it looks inconsistent). Question: What’s the correct way in iOS 26 to keep a custom row tint and get the system-style rounded corners / liquid-glass effect while swiping?
Topic: UI Frameworks SubTopic: SwiftUI
0
1
91
Dec ’25
Why is ScreenCaptureKit throttled to about 7 fps?
I have an app that records a 32 x 32 rect under the cursor as the user moves it around and it sends it to Flutter. It suffers from major lag. Instead of getting 30 fps, I get about 7 fps. That is, there are significant lags between screen grabs. This on an Intel Mac mini x64 with 15.7.3 and one display. flutter: NATIVE: ExplodedView framesIn=2 timeSinceStart=1115.7ms gapSinceLastFrame=838.8ms flutter: NATIVE: ExplodedView framesIn=4 timeSinceStart=1382.6ms gapSinceLastFrame=149.9ms flutter: NATIVE: ExplodedView framesIn=5 timeSinceStart=1511.0ms gapSinceLastFrame=128.4ms flutter: NATIVE: ExplodedView framesIn=7 timeSinceStart=1698.3ms gapSinceLastFrame=102.9ms flutter: NATIVE: ExplodedView STOP polling totalTime=4482.6ms framesIn=28 framesSent=28 acks=28 Here's a testable excerpt: import ScreenCaptureKit import CoreMedia import CoreVideo import QuartzCore final class Test: NSObject, SCStreamOutput, SCStreamDelegate { private let q = DispatchQueue(label: "cap.q") private var stream: SCStream? private var lastFrameAt: CFTimeInterval = 0 private var frames = 0 func start() { SCShareableContent.getExcludingDesktopWindows(false, onScreenWindowsOnly: true) { content, err in guard err == nil, let display = content?.displays.first else { print("shareableContent error: \(String(describing: err))"); return } let filter = SCContentFilter(display: display, excludingWindows: []) let config = SCStreamConfiguration() config.showsCursor = false config.queueDepth = 1 config.minimumFrameInterval = CMTime(value: 1, timescale: 30) config.pixelFormat = kCVPixelFormatType_32BGRA config.width = 32 config.height = 32 config.sourceRect = CGRect(x: 100, y: 100, width: 32, height: 32) let s = SCStream(filter: filter, configuration: config, delegate: self) try! s.addStreamOutput(self, type: .screen, sampleHandlerQueue: self.q) self.stream = s s.startCapture { startErr in print("startCapture err=\(String(describing: startErr))") } // Optional: move sourceRect at 30Hz (cursor-follow simulation) Timer.scheduledTimer(withTimeInterval: 1.0/30.0, repeats: true) { _ in let c2 = SCStreamConfiguration() c2.showsCursor = false c2.queueDepth = 1 c2.minimumFrameInterval = CMTime(value: 1, timescale: 30) c2.pixelFormat = kCVPixelFormatType_32BGRA c2.width = 32 c2.height = 32 let t = CACurrentMediaTime() c2.sourceRect = CGRect(x: 100 + (sin(t) * 50), y: 100, width: 32, height: 32) s.updateConfiguration(c2) { _ in } } } } func stream(_ stream: SCStream, didOutputSampleBuffer sb: CMSampleBuffer, of type: SCStreamOutputType) { guard type == .screen else { return } let now = CACurrentMediaTime() let gapMs = (lastFrameAt == 0) ? 0 : (now - lastFrameAt) * 1000 lastFrameAt = now frames += 1 if frames <= 10 || frames % 60 == 0 { print("frames=\(frames) gapMs=\(String(format: "%.1f", gapMs))") } } }
0
0
128
Dec ’25
UICollectionView cells don't show accessibility numbers or labels
I started to use the Accessibility features of UIKit but cannot get the numbers or labels to show up on UICollectionCells. The image here shows a 3x3 matrix with no numbers, but the numbers on the menu commands show up. Actually these are just iOS accessibility features, not my app. I've tried reducing the size of my images or no images, but nothing shows up (in any of my UICollection code). I can get them to work on UITableView cells. I've tried the Accessibility selection in the storyboard or code, but nothing helps.
0
0
166
Dec ’25
Navigation title flickers when tab is changed when used with a List / Form
Problem When a List / Form is added inside a TabView and navigationTitle is set, then switching between tabs causes the navigation title to flicker. Feedback: FB21436493 Environment Xcode: 26.2 (17C52) iOS: 26.2 (23C55) Reproducible on: Both simulator and device Root cause When List / Form is commented out, issue doesn't occur Steps to Reproduce Run app on iOS Switch between tabs Notice that the navigation title flickers Code ContentView import SwiftUI struct ContentView: View { @State private var selectedTab = TabItem.red var body: some View { NavigationStack { TabView(selection: $selectedTab) { ForEach(TabItem.allCases, id: \.self) { tab in Tab(tab.rawValue, systemImage: tab.systemImageName , value: tab) { // Problem occurs with a List / Form // Commenting out list works without flickering title List { Text(tab.rawValue) } } } } .navigationTitle(selectedTab.rawValue) } } } TabItem enum TabItem: String, CaseIterable { case red case green case blue var systemImageName: String { switch self { case .red: "car" case .green: "leaf" case .blue: "bus" } } } Screen recording:
Topic: UI Frameworks SubTopic: SwiftUI
3
0
276
Dec ’25
DMG - Background - Broken in Tahoe ?
I am trying to set an image as the background in the window of a DMG. The image is: PNG file; 144x144 resolution; 1138x574 size. In macOS Tahoe, the image is added by: selecting the DMG window; opening the "Show View Options" dialog; clicking on "Picture"; dragging the image file to the small square box labelled "Drag image here"; closing "Show View Options" dialog. The DMG is then ejected. In Disk Utility, the image file is converted to "Read Only image (UDRO)". The converted image file is opened and the background image is visible. The image file is then copied to a MacBook running macOS 12 Monterey and opened. The background image is NOT shown. The image file is copied to a Mac mini running macOS 14 Sequoia and opened. The background image is NOT shown. Have read past online discussions in which it was explained that an image file called "background" should be inside a hidden folder called ".background". The above procedure did not do that. Is that old advice still correct for macOS Tahoe ? Has Tahoe somehow broken the method used for setting the background of a Window ? Is the method used in Tahoe different to past versions of macOS ? If so, is there a way of maintaining compatibility with old versions of macOS ? Is there any documentation on how to set the background image of a DMG window which might explain this behaviour ?? Thanks.
Topic: UI Frameworks SubTopic: General Tags:
0
0
131
Dec ’25
iPadOS 26.x ignores supportedInterfaceOrientations on iPad when device orientation lock is OFF
Environment Device: iPad Air (5th generation, M1) OS Version: iPadOS 26.1 Device Orientation Lock: OFF Stage Manager / Multitasking: Disabled App Mode: Full screen (UIRequiresFullScreen = true) Supported Orientations: iPhone: Portrait + Landscape iPad: Landscape only Description On iPadOS 26.x, when device orientation lock is OFF, iPad apps that support only landscape orientation can be displayed in portrait orientation, even though portrait is explicitly not supported for iPad. This issue: Occurs not only at app launch Can also happen during runtime, such as: Returning to the app from background Unlocking the device Rotating the device while the app is running Switching focus (Control Center, Notification Center, multitasking gestures) When orientation lock is ON, the system consistently respects the app’s supported interface orientations and the issue does not occur. This behavior is a regression in iPadOS 26.x. Expected Behavior Regardless of device orientation lock state: The system should never display an app in an unsupported orientation supportedInterfaceOrientations must always be enforced Physical device orientation should only be applied within supported orientations Actual Behavior With orientation lock OFF: The system can force the app into portrait orientation This happens even though portrait is not listed in UISupportedInterfaceOrientations~ipad The app UI becomes incorrectly laid out or broken With orientation lock ON: Orientation behavior is correct and stable This suggests iPadOS 26.x is allowing device orientation to override supportedInterfaceOrientations during runtime. Info.plist Configuration UIRequiresFullScreen UISupportedInterfaceOrientations UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight UISupportedInterfaceOrientations~ipad UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight
Topic: UI Frameworks SubTopic: General
0
0
159
Dec ’25
In Mac app, when the Settings view that uses `@Environment(\.dismiss)` it causes the subview's models to be created multiple times.
Problem For a mac app, when the Settings view that uses @Environment(\.dismiss) it causes the subview's models to be created multiple times. Environment macOS: 26.2 (25C56) Feedback FB21424864 Code App @main struct DismissBugApp: App { var body: some Scene { WindowGroup { ContentView() } Settings { SettingsView() } } } ContentView struct ContentView: View { var body: some View { Text("Content") } } SettingsView struct SettingsView: View { @Environment(\.dismiss) private var dismiss var body: some View { VStack { Text("Settings") SectionAView() } } } SectionAView struct SectionAView: View { @State private var model = SectionAViewModel() var body: some View { Text("A") .padding(40) } } SectionAViewModel @Observable class SectionAViewModel { init() { print("SectionAViewModel - init") } deinit { print("SectionAViewModel - deinit") } } Steps to reproduce (refer to the attached video) 1 - Run the app on the mac 2 - Open app's Settings 3 - Notice the following logs being printed in the console: SectionAViewModel - init SectionAViewModel - init 4 - Tap on some other app, so that the app loses focus 5 - Notice the following logs being printed in the console: SectionAViewModel - init SectionAViewModel - deinit 6 - Bring the app back to focus 7 - Notice the following logs being printed in the console: SectionAViewModel - init SectionAViewModel - deinit Refer to screen recording
Topic: UI Frameworks SubTopic: SwiftUI
0
0
169
Dec ’25
Using Content Inset Adjustments on macOS Tahoe with Liquid Glass in nested NSScrollViews inside Sidebar
I have the following code (compile as a standalone file): #import <Cocoa/Cocoa.h> @interface AppDelegate : NSObject <NSApplicationDelegate> @property (strong) NSWindow *window; @end @implementation AppDelegate - (void)applicationDidFinishLaunching:(NSNotification *)notification { // Create main window self.window = [[NSWindow alloc] initWithContentRect:NSMakeRect(100, 100, 800, 600) styleMask:(NSWindowStyleMaskTitled | NSWindowStyleMaskClosable | NSWindowStyleMaskResizable | NSWindowStyleMaskMiniaturizable) backing:NSBackingStoreBuffered defer:NO]; [self.window setTitle:@"Nested ScrollView Demo"]; [self.window makeKeyAndOrderFront:nil]; // Split view controller NSSplitViewController *splitVC = [[NSSplitViewController alloc] init]; // Sidebar NSViewController *sidebarVC = [[NSViewController alloc] init]; sidebarVC.view = [[NSView alloc] initWithFrame:NSMakeRect(0, 0, 200, 600)]; sidebarVC.view.wantsLayer = YES; NSSplitViewItem *sidebarItem = [NSSplitViewItem sidebarWithViewController:sidebarVC]; sidebarItem.minimumThickness = 150; sidebarItem.maximumThickness = 400; [splitVC addSplitViewItem:sidebarItem]; // Content view controller NSViewController *contentVC = [[NSViewController alloc] init]; // Vertical scroll view (outer) NSScrollView *verticalScrollView = [[NSScrollView alloc] initWithFrame:NSMakeRect(0, 0, 600, 600)]; verticalScrollView.automaticallyAdjustsContentInsets = YES; verticalScrollView.hasVerticalScroller = YES; verticalScrollView.hasHorizontalScroller = NO; verticalScrollView.autoresizingMask = NSViewWidthSizable | NSViewHeightSizable; NSView *verticalContent = [[NSView alloc] initWithFrame:NSMakeRect(0, 0, 600, 1200)]; verticalContent.wantsLayer = YES; verticalContent.layer.backgroundColor = [[NSColor blueColor] CGColor]; [verticalScrollView setDocumentView:verticalContent]; // Add several horizontal scroll sections CGFloat sectionHeight = 150; for (int i = 0; i < 5; i++) { // Horizontal scroll view inside section NSScrollView *horizontalScroll = [[NSScrollView alloc] initWithFrame:NSMakeRect(0, verticalContent.frame.size.height - (i+1)*sectionHeight - i*20, 600, sectionHeight)]; horizontalScroll.hasHorizontalScroller = YES; horizontalScroll.hasVerticalScroller = NO; horizontalScroll.autoresizingMask = NSViewWidthSizable | NSViewHeightSizable; NSView *horizontalContent = [[NSView alloc] initWithFrame:NSMakeRect(0, 0, 1200, sectionHeight)]; horizontalContent.wantsLayer = YES; // Add labels horizontally for (int j = 0; j < 6; j++) { NSTextField *label = [NSTextField labelWithString:[NSString stringWithFormat:@"Item %d-%d", i+1, j+1]]; label.frame = NSMakeRect(20 + j*200, sectionHeight/2 - 15, 180, 30); [horizontalContent addSubview:label]; } horizontalScroll.documentView = horizontalContent; [verticalContent addSubview:horizontalScroll]; } contentVC.view = verticalScrollView; NSSplitViewItem *contentItem = [NSSplitViewItem splitViewItemWithViewController:contentVC]; contentItem.automaticallyAdjustsSafeAreaInsets = YES; contentItem.minimumThickness = 300; [splitVC addSplitViewItem:contentItem]; self.window.contentViewController = splitVC; // Sidebar label NSTextField *label = [NSTextField labelWithString:@"Sidebar"]; label.translatesAutoresizingMaskIntoConstraints = NO; [sidebarVC.view addSubview:label]; [NSLayoutConstraint activateConstraints:@[ [label.centerXAnchor constraintEqualToAnchor:sidebarVC.view.centerXAnchor], [label.centerYAnchor constraintEqualToAnchor:sidebarVC.view.centerYAnchor] ]]; } @end int main(int argc, const char * argv[]) { @autoreleasepool { NSApplication *app = [NSApplication sharedApplication]; AppDelegate *delegate = [[AppDelegate alloc] init]; [app setDelegate:delegate]; [app run]; } return 0; } Obviously, since the contents of the right part (the content of the sidebar) has its content inset, the horizontal scrolling views cannot extend to the left beneath the sidebar. I can change line 39 to say verticalScrollView.automaticallyAdjustsContentInsets = NO; which will make the inner horizontal scroll views able to extend below the sidebar, but then I'd lose out on the automatic inset management to not have other content overlap beneath the sidebar. So what can I do here? I've tried manually changing the frame of the inner scroll views to start on a negative x, but that does not allow me to scroll all the way to the leftmost content. I'm hoping I won't have to adjust for safe areas manually for the outer scroll view. I'd also appreciate tips on how to fix the fact that veritical scrolling doesn't work when your mouse is in a horizontal scroll view. Thanks! P.S. same thing also exists on UIKit.
0
0
153
Dec ’25