Provide views, controls, and layout structures for declaring your app's user interface using SwiftUI.

SwiftUI Documentation

Posts under SwiftUI subtopic

Post

Replies

Boosts

Views

Activity

Why doesn't .glassEffect tint render on a Menu in an iOS 26 toolbar?
This is what I am trying to achieve (from the Phone app, similar one is also in Photos) I have a standard SwiftUI Menu in a toolbar with a glass tint applied to indicate the filter is active: Menu { // …filter options } label: { Label("Filter", systemImage: "line.3.horizontal.decrease") } .glassEffect(.regular.tint(.accentColor).interactive()) The glass effect doesn't render at all, no tint. The button looks completely unstyled. If I switch the label from Label to Image, the glass renders, but as a stretched oblong pill. I have tried several other combinations too: Also in the Apple's version during hover (iPad) the highlight aligns with the tint itself (see second image above) rather than outside it like in example 3 from the list above: Is there a way to get a Menu's trigger inset tint to look as in the Phone app example?
0
0
88
1w
"any View cannot conform to View"
Hello, What is the solution to this problem, assuming that you are not supposed to use AnyView, which I hear over and over again? Given this protocol: protocol MyProtocol { associatedtype V: View var content: () -> V { get } } if I want to store a heterogenous collection of MyProtocol, let collection: [any MyProtocol], then the underlying V type of each is erased to any View, which (supposedly) does not conform to View. Is there no way to "unbox" the existential any View to get the underlying View back? That unboxing idea is something I heard in a few WWDC videos but it seems like it does not apply to View.
Topic: UI Frameworks SubTopic: SwiftUI
0
0
64
1w
SwiftUI NavigationSplitView sidebar toolbar has excessive top inset when embedded in TabView since iPadOS 26.4
I’m seeing a layout regression in SwiftUI on iPadOS 26.4 involving NavigationSplitView inside a TabView. When a NavigationSplitView is embedded in a TabView, the sidebar toolbar appears to reserve too much vertical space. There is a large vertical gap between the top edge of the sidebar and the sidebar collapse/toggle icon. It looks as if the sidebar toolbar itself has become much taller than expected. The same NavigationSplitView layout is rendered correctly when it is shown directly without being embedded in a TabView. Environment: iPadOS 26.4 or later SwiftUI iPad TabView NavigationSplitView inside one tab Expected behavior The sidebar toolbar should use its normal height, as it does when the same NavigationSplitView is shown without a surrounding TabView. The sidebar collapse/toggle icon should appear close to the top of the sidebar, without a large empty gap above it. Actual behavior When the NavigationSplitView is hosted inside a TabView, the sidebar toolbar area becomes excessively tall. A large empty space appears above the sidebar collapse/toggle icon. This only happens in the TabView setup. Rendering the same NavigationSplitView directly does not show the issue. Feedback I also filed this as Feedback Assistant report: FB22645938 Has anyone else seen this behavior since iPadOS 26.4? Is this an intentional layout change, or is there a supported way to avoid this additional top inset when using NavigationSplitView inside TabView? Reproduction import SwiftUI struct ContentView: View { enum AppTab { case first case second } @State private var selectedTab: AppTab = .first var body: some View { TabView(selection: $selectedTab) { Tab("First", systemImage: "sidebar.leading", value: .first) { NavigationSplitView { List { Section("Sidebar Content") { ForEach(1...20, id: \.self) { index in Text("Item \(index)") } } } .navigationTitle("Sidebar") .toolbar { ToolbarItem(placement: .topBarLeading) { Button { // action } label: { Image(systemName: "plus") } } } } detail: { Text("Detail") } } Tab("Second", systemImage: "doc", value: .second) { Text("Second tab") } } } }
0
0
181
2w
HSplitView resize cursor missing when split view is conditionally rendered (FB22712819)
Hey all, Ran into a fun one on macOS 26.4.1 / Xcode 26.4.1, and I think I've narrowed it down enough to be worth sharing. Symptom: HSplitView's divider drags fine, but the cursor never changes to the resize cursor on hover. Just stays as the regular arrow. The cause (in my case): the HSplitView was conditionally rendered via an outer if let: struct PlayerDetailsView: View { let theme: Theme var playerVM = PlayerViewModel.shared var body: some View { let grayscaleCM = ColorMap(table: .grayscale) ZStack { VStack(spacing: 0) { Rectangle() .fill(LinearGradient(colors: [Color.black.opacity(0.45), Color.black.opacity(0)], startPoint: .top, endPoint: .bottom)) .frame(height: 8) Spacer() Rectangle() .fill(LinearGradient(colors: [Color.black.opacity(0.45), Color.black.opacity(0)], startPoint: .bottom, endPoint: .top)) .frame(height: 8) } .allowsHitTesting(false) if let disc = playerVM.disc { HSplitView { DiscInfoView( disc: disc, theme: theme, ) .frame(minWidth: 720, alignment: .topLeading) .buttonShadow() .focusable(false) TrackListView( theme: theme, playbackSequence: playerVM.tracksInPlaybackSequence, bonusTrackStartIndex: playerVM.player.disc?.releaseMetadata?.firstBonusTrackIndex, bonusTracksTitle: playerVM.player.disc?.releaseMetadata?.bonusTracksTitle, bonusTracksDisabled: playerVM.bonusTracksDisabled, onBonusIconTap: { playerVM.player.bonusTracksDisabled.toggle() } ) .frame(minWidth: 512) .focusable(false) } } } .background( LinearGradient( colors: [ grayscaleCM.color(for: 0.23), grayscaleCM.color(for: 0.17), ], startPoint: .top, endPoint: .bottom ) ) } } The fix: move the conditional inside the HSplitView, so the split view itself is always present in the hierarchy (swap line 21 and 22 of code above): HSplitView { if let disc = playerVM.disc { DiscInfoView( disc: disc, theme: theme, ) .frame(minWidth: 720, alignment: .topLeading) .buttonShadow() .focusable(false) TrackListView( theme: theme, playbackSequence: playerVM.tracksInPlaybackSequence, bonusTrackStartIndex: playerVM.player.disc?.releaseMetadata?.firstBonusTrackIndex, bonusTracksTitle: playerVM.player.disc?.releaseMetadata?.bonusTracksTitle, bonusTracksDisabled: playerVM.bonusTracksDisabled, onBonusIconTap: { playerVM.player.bonusTracksDisabled.toggle() } ) .frame(minWidth: 512) .focusable(false) } } I asked Claude AI about it and its guess is that conditionally inserting the HSplitView causes its underlying NSSplitView to get torn down and rebuilt on view updates, and the tracking areas responsible for the resize cursor never get a chance to settle. But that would be great to have a confirmation from someone at Apple who knows what's happening under the hood. Is this a known issue or an Expected behavior? Filed as FB22712819 in case anyone wants to duplicate. I posted this in case anyone had the same very specific issue... Cheers!
Topic: UI Frameworks SubTopic: SwiftUI
0
0
125
2w
How can I intercept Shift+Tab in SwiftUI on macOS?
Hi everyone, I'm building a macOS SwiftUI app and I'm trying to intercept both: Tab Shift + Tab to perform custom actions (similar to how text editors indent/outdent items). Right now, plain Tab works fine, but Shift + Tab never reaches my .onKeyPress(.tab) handler. Here's what I'm currently trying: import SwiftUI struct ShiftTabNotIntercepted: View { @State private var shiftKeyPressed = false var body: some View { Text("Hello") .focusable() .onKeyPress(.tab) { print("tab pressed with shift: \(shiftKeyPressed)") return .handled } .onModifierKeysChanged(mask: .shift) { old, new in shiftKeyPressed = new.contains(.shift) } } } Behavior: Pressing Tab prints: tab pressed with shift: false Pressing Shift + Tab does nothing — .onKeyPress(.tab) never fires. I also noticed: if a sidebar is visible, Shift + Tab moves focus to the sidebar if no sidebar is visible, it still doesn't trigger the handler So it seems macOS is intercepting Shift + Tab for focus navigation before SwiftUI sees it. My goal is to fully own this keyboard behavior for a custom outline/tree editor UI. Questions: Is there a SwiftUI-native way to intercept Shift + Tab? Is .onKeyPress fundamentally unable to capture this combination? Do I need to drop down to AppKit (NSViewRepresentable, keyDown, etc.) to reliably handle it? Thanks!
1
0
150
2w
.buttonStyle(.glass) background changes abruptly between 50pt and 51pt in dark mode
[Submitted as FB22612121] A SwiftUI Button using .buttonStyle(.glass) with .buttonBorderShape(.capsule) changes its background abruptly when its size goes from 50×50 to 51×51 points in dark mode. This appears to be a threshold in opacity/material rather than a smooth size-based change. The sample shows identical buttons at 40, 50, 51, and 60 points, with a clear jump between 50 and 51. Measured RGB values shift from 19,19,19 to 30,30,30. The effect also varies with the background, which points to a material/opacity change rather than a fixed fill. ENVIRONMENT iOS 26.4.1 (23E254a) iOS 26.5 (23F5059e) REPRO STEPS Create a new iOS SwiftUI project. Replace ContentView with the sample code below. Run the app or open ContentView in SwiftUI Preview (dark mode). Observe the buttons at 40×40, 50×50, 51×51, and 60×60. Compare the 50pt and 51pt buttons. ACTUAL The background changes abruptly between 50pt and 51pt. The 51pt button uses a noticeably different opacity/material, producing a visible jump in dark mode. EXPECTED The glass background should remain visually consistent or change smoothly as size changes by 1 point. 50pt and 51pt buttons should not have a discontinuous difference. SCREENSHOT SAMPLE CODE struct ContentView: View { private let sizes: [CGFloat] = [40, 50, 51, 60] var body: some View { ScrollView { VStack(alignment: .leading, spacing: 16) { Text("Glass button dark-mode size jump") .font(.headline) Text("All buttons use .buttonStyle(.glass). Only the label frame changes.") .font(.footnote) .foregroundStyle(.secondary) ForEach(Array(sizes.enumerated()), id: \.offset) { index, size in HStack(spacing: 14) { Button { } label: { Text("\(index + 1)") .font(.system(size: size * 0.42, weight: .medium)) .frame(width: size, height: size) } .buttonStyle(.glass) .buttonBorderShape(.capsule) Text("label frame: \(Int(size)) x \(Int(size))") .font(.callout.monospacedDigit()) .foregroundStyle(.secondary) } } } .padding(24) } .preferredColorScheme(.dark) } }
Topic: UI Frameworks SubTopic: SwiftUI
1
0
208
2w
iOS 18.6.2 issue with "let"
I am facing an issue in SwiftUI on iOS 18.6.2 where passing a value to a destination view during navigation is not working as expected. In my implementation, I pass a billerId as a constant (let) to the destination view (BillersItemView) using NavigationLink. This approach works correctly across all previous iOS versions. However, on iOS 18.6.2, the destination view does not receive the updated value properly. Before triggering navigation, the value is correctly updated in the ViewModel, but the destination view seems to receive an incorrect or stale value, which affects further API calls and UI rendering. This pattern of passing immutable (let) values is used throughout the app and has always worked reliably, so this behavior appears inconsistent and possibly related to changes in SwiftUI navigation handling in iOS 18.6.2. Could you please confirm if this is a known issue or if there are any recommended changes or workarounds to ensure correct data passing in this scenario? It can be very likely a SwiftUI navigation state timing issue that became more visible in iOS 18.x, especially with NavigationLink(isActive:) + external @ObservedObject updates. But i need to know why this is working in others. I have attached the relevant code for your reference. import SwiftUI struct CategoryBillersView: View { @ObservedObject var billPaymentsVM: BillPaymentsViewModel @State private var goToBillerItem = false var body: some View { NavigationView { VStack { NavigationLink(isActive: $goToBillerItem) { BillersItemView( billPaymentsVM: billPaymentsVM, billerId: billPaymentsVM.selectedBillerId ) } label: { EmptyView() } Button("Go to Biller") { billPaymentsVM.selectedBillerId = 123 goToBillerItem = true } } } } } struct BillersItemView: View { @ObservedObject var billPaymentsVM: BillPaymentsViewModel let billerId: Int var body: some View { Text("Biller ID: \(billerId)") .onAppear { billPaymentsVM.fetchBiller(billerId: billerId) } } } class BillPaymentsViewModel: ObservableObject { @Published var selectedBillerId: Int = 0 }
Topic: UI Frameworks SubTopic: SwiftUI
0
0
61
2w
How to achieve this vibrant background effect on iOS?
Hi everyone, I'm trying to reproduce an effect that Apple has created for the Contacts app on iOS, iPadOS and MacOS v26.4 where the contact card is displayed with a nice material frosted background that blends well with the underlying background. I love this effect and I want to use it in my app to display different information. As you can see in the screenshot, the list rows have a frosted background (probably thinMaterial) combined with a vibrant effect that adapts to the underlying view background. Additionally, the fields labels and icons also have a nice effect. I've tried everything but I'm unable to accurately recreate this effect. I tried applying a Rectangle with a material background listRowBackground but this resulted in something different than what Apple is using (either too light, too dark, or simply not vibrant). I've even tried SwiftUIVisualEffects swift package which can apply a vibrancy effect. However the result is still not the same as the one you see in the screenshot, with the correct contrast between background and labels. Any guidance would be appreciated. Thank you 🙏🏻
4
0
400
2w
Right Way of Positioning an Always Visible Overlay on Top of Navigation Bar That Aligns With Other Navigation Items
Starting with Liquid Glass, the navigation items seem not to be vertically centered within the navigation bar. This makes it very challenging to position an overlay on top of the navigation bar so that it aligns naturally with other elements such as the back button, dismiss button, and others. We want to achieve this for a progress bar so that it remains visible regardless of which views are pushed underneath. Therefore, we cannot add it as a navigation item on each screen, as doing so would cause the progress bar to animate repeatedly as new screens are pushed onto the stack. This used to be easier pre liquid glass since navigation items were centered vertically within the navigation bar. The approach I tried to center the progress bar in the navigation bar: Get access to the top safe area insets through GeometryReader Get access to the the status bar height through UIWindowScene's statusBarManager Subtract status bar height from top safe area inset to calculate the navigation bar height Update the padding of the progress bar accordingly to make sure it is centered within the navigation bar This works, but as I mentioned, now the navigation items are not centered, and the amount of vertical offset they have seems to differ from one screen to another, making it impossible to come up with an additional padding value to align across devices. See how the navigation item looks like within the navigation bar in the view debugger (doesn't matter if it is UINavigationController or NavigationStack the behaviour is the same, also please note that the positioning is the same for a view without an explicit leading toolbar item, where the default back button is provided by the system when a view is pushed): Existing code (without any hacky solutions) to add a progress bar on top as overlay: struct ContentView: View { @State var shouldShowOverlay = false var body: some View { NavigationStack { NavigationLink("Go to View2") { View2() } .navigationBarTitleDisplayMode(.inline) .toolbar { ToolbarItem(placement: .topBarLeading) { Button { } label: { Image(systemName: "chevron.left") } } } } .overlay(alignment: .top) { ProgressView(value: 0.5) .frame(width: 200) // what to add as padding here // .padding(.top, 16.0) } } How it looks: Some additional observations for the navigation bar item here: There seems to be 4 _UINavigationBarPlatterAnimationViews in the view stack, prior to the bar button item:
 The first two seems to be fine, they both have (0, 0, 44, 44) for both frame and bounds
 The third one’s frame has height and width of 48.2, and x, y values of -2.1. The last one’s frame has 40,17 for height and width and 1.92 for x,y values. Both views have the following bounds: (0, 0, 44, 44). I also tried to access to the origin of the back bar button item so that I could calculate where the position the overlay, but that also didn't yield to something useful, not to mention it would also be a super hacky solution. So my ultimate question is, is there a clean way to position an overlay on top of the navigation bar that vertically aligns with other navigation bar items, or should we just position it elsewhere and do not mess with navigation bar anymore? Any input would be greatly appreciated.
0
1
180
2w
apply .activityBackgroundTint modifier in smartstack
On iOS 26, when using .activityBackgroundTint modifiers to change the background color in the Activity Kit, the changes do not appear to apply correctly in Smart Stack. While the color changes as expected, the background is rendered as simply transparent without a glass effect which reduces readability. The glass effect is applied only when activityBackgroundTint is not used.
0
0
220
2w
Having trouble with RawRespresentable "Expected to decode String but found a dictionary instead."
I want to use AppStorage for a custom struct I am using struct Activities { var name: String var age: Int } struct ContentView: View { @AppStorage("key") private var activities: Activities = .init(name: "Albert", age: 42) var body: some View { VStack { TextField("Activity Name", text: $activities.name) } } } The above code generates a compiler warning, recommending I add RawRepresentable conformance. So I've added it like this: extension Activities: RawRepresentable { public init?(rawValue: String) { guard let data = rawValue.data(using: .utf8) else { return nil } do { let result = try JSONDecoder().decode(Activities.self, from: data) self = result } catch { print(error) return nil } } var rawValue: String { guard let data = try? JSONEncoder().encode(self), let result = String(data: data, encoding: .utf8) else { return "{}" } return result } } This leads to a stack overflow because calling encode from rawValue calls rawValue. :-( I overcame this by declaring Codable conformance and overriding the default Encodable implementation: extension Activities: Codable { enum CodingKeys: String, CodingKey { case name case age } func encode(to encoder: any Encoder) throws { var container = encoder.container(keyedBy: CodingKeys.self) try container.encode(name, forKey: .name) try container.encode(age, forKey: .age) } } This solves the stack overflow, but now init?(rawValue: String) is failing and I'm not sure why. When I set a breakpoint in my catch block I see the following: (lldb) po error ▿ DecodingError ▿ typeMismatch : 2 elements - .0 : Swift.String ▿ .1 : Context - codingPath : 0 elements - debugDescription : "Expected to decode String but found a dictionary instead." - underlyingError : nil (lldb) po rawValue {"name":"Albert2","age":42} (lldb) po data ▿ 27 bytes - count : 27 ▿ bytes : 27 elements - 0 : 123 - 1 : 34 - 2 : 110 - 3 : 97 - 4 : 109 - 5 : 101 - 6 : 34 - 7 : 58 - 8 : 34 (truncated to save space for posting :-)
2
0
483
2w
SwiftUI Text rendering with too small height / one line missing causing unexpected text truncation on iPhone devices
FB: FB22577211 The following trivial SwiftUI Text rendering causes wrong text layout and truncated text. The text should take the required height to render the text without truncation. Adding fixedSize does also not solve this. This bug only happens on devices and not on the simulator. Confirmed with iPhone 15 and iOS 26.4.1 but my colleague used another iPhone so it’s multiple iPhone devices. import SwiftUI let txt = """ Es sollte die erste Japan-Tournee von vielen werden, kein anderes Land – abgesehen von Österreich und der Schweiz – bereisten die Berliner Philharmoniker häufiger. Wie kam es zu dem überschäumend herzlichen Empfang, der dem Orchester bei seinem ersten Gastspiel in Tokio bereitet wurde und wie wurde das Land zu einer »zweiten Heimat« für die Berliner? Ein konkreter historischer Grundstein für das hohe Ansehen klassischer Musik »made in Germany« in Japan wurde bereits im 19. Jahrhunderts gelegt: Als Teil von umfassenden gesellschaftlichen Modernisierungsmaßnahmen vergab die Regierung ab 1868 Stipendien an junge japanische Intellektuelle, damit diese an den besten internationalen Instituten studieren konnten. Berlin wurde – neben Wien – als globales Zentrum der Musik betrachtet, und so erhielten viele japanische Studierende um die Jahrhundertwende die Gelegenheit, von Komponisten wie etwa Max Bruch zu lernen. Zurück in der Heimat, teilten sie ihre Begeisterung für die europäische Kunstmusik sowie das Wissen um die instrumentale und kompositorische Praxis der klassisch-romantischen Tradition. """ struct ContentView: View { var body: some View { VStack { Text(txt) } .padding(.leading, 20) .padding(.trailing, 20) .frame(maxWidth: .infinity) } } This is also enough: Text(txt) .padding(.horizontal, 20) .fixedSize(horizontal: false, vertical: true) Expected: Text is rendered without truncation / ellipsis. Actual: Text is rendered with too small height / missing one line so it’s truncated / with ellipsis.
10
0
601
2w
tabViewBottomAccessory does not inherit tab bar vibrancy / foregroundStyle behavior
Hi, I’m experimenting with the new tabViewBottomAccessory API and I’m running into an inconsistency with how colors are handled compared to the native tab bar items. Context When using a TabView, the system tab bar automatically adapts its foreground color (icons and labels) based on the background content (light/dark, images, etc.). This is the expected “vibrancy” behavior. However, when adding content via .tabViewBottomAccessory, the foreground color does not seem to follow the same logic. Minimal example : import SwiftUI struct ContentView: View { var body: some View { TabView { Tab("Home", systemImage: "house") { Text("Home") .frame(maxWidth: .infinity, maxHeight: .infinity) .ignoresSafeArea() } Tab("New", systemImage: "squareshape.split.2x2") { Text("New") .frame(maxWidth: .infinity, maxHeight: .infinity) .foregroundStyle(.white) .background(Color.black) .ignoresSafeArea() } } .tabViewBottomAccessory { HStack { Image(systemName: "command.square") Text("Message test") Spacer() Image(systemName: "play.fill") } .padding(.horizontal, 20) .foregroundStyle(.primary) } } } Observed behavior Tab bar icons and labels correctly switch between dark and light depending on the background. Content inside .tabViewBottomAccessory remains black, even when .foregroundStyle(.primary) is used. Expected behavior I would expect .tabViewBottomAccessory content to: Either inherit the same vibrancy/foreground adaptation as the tab bar items Or have a documented way to match that behavior I want to reuse the Apple Music Navigation
Topic: UI Frameworks SubTopic: SwiftUI
0
0
85
2w
SwiftUI TabView(.sidebarAdaptable) does not reliably animate content resize when switching between sidebar and top tab bar on iPad
Hi everyone, I’m building an iPad app in SwiftUI using the adaptive tab navigation pattern: Tab(value: .overview) { OverviewView() } label: { Label("Overview", systemImage: "archivebox") } Tab(value: .gallery) { GalleryView() } label: { Label("Gallery", systemImage: "shippingbox") } Tab(value: .canvas) { CanvasView() } label: { Label("Canvas", systemImage: "rectangle") } Tab(value: .record) { recordView } label: { Label("Record", systemImage: "plus") } } .tabViewStyle(.sidebarAdaptable) .tabViewCustomization($tabCustomization) The issue is that when the adaptive tab bar switches between the sidebar placement and the top bar placement on iPad, the content area resize animation is unreliable. The system navigation chrome changes correctly, but some tab contents jump directly to their final width instead of smoothly animating with the sidebar/top bar transition. Interestingly, one of my record views appears to animate consistently, so it seems the system transition itself is possible, but some view hierarchy or navigation structure may be preventing the animation in other tabs. Each major tab currently owns its own NavigationStack. For example, OverviewView, GalleryView, and CanvasView each have a NavigationStack as their root view. The Record tab conditionally shows different recording views, and one of those views also contains its own NavigationStack. I have already tried several approaches, but none solved the issue reliably: Observing @Environment(.tabBarPlacement) and adding .animation(..., value:) Reporting tabBarPlacement upward using a PreferenceKey and wrapping the update in withAnimation Wrapping tab contents in GeometryReader or other outer layout containers Temporarily removing .tabViewCustomization($tabCustomization) and .customizationID(...) Reducing the implementation to the simplest documented TabView(selection:) + Tab(...) + .tabViewStyle(.sidebarAdaptable) structure Some of these attempts actually made the animation behavior worse, so I reverted them. My questions are: 1.Is the content area expected to animate automatically when TabView(.sidebarAdaptable) changes between sidebar and top bar placement on iPad? 2.Is it recommended for each tab to own its own NavigationStack in this setup? 3.Could tabViewCustomization(:) or customizationID(:) affect the sidebar/top bar transition animation? 4.Is there an official SwiftUI pattern for preserving the system animation transaction during this adaptive tab bar placement change? 5.If this is expected behavior or a current limitation, what structure would Apple recommend for this kind of iPad navigation? Thanks in advance!
Topic: UI Frameworks SubTopic: SwiftUI
0
0
99
2w
Styling LabeledContent inside a Form on macOS?
On macOS 26, the Label part of a LabeledContent control and the Section.header part of a Section do not seem to honour view modifiers like .controlSize(.small) when used inside a Form with .formStyle(.grouped). Is there a way to make them respect the control size? Example: Form { Section("Details") { LabeledContent("Company", value: "Apple") } } .formStyle(.grouped) .controlSize(.small) // This only effects 'Apple' This produces a view where the value "Apple" is using a smaller font size but the label and the section header are not. I've tried (I think) almost every variation I can think of in terms of creating a LabeledContent and applying .controlSize but all of them come up short. The Form appears to always override my view modifiers for the section heading and label. Example 2: Form { Section { LabeledContent { Text("Company") .controlSize(.small) // Has no effect. } label: { Text("Apple") // Correctly resized to .small. } } header: { Text("Details") .controlSize(.small) // Has no effect. } } .formStyle(.grouped) .controlSize(.small) The best I've been able to come up with is a custom LabeledContentStyle that manually applies the layout and the styling, but that requires I explicitly "recreate" the macOS look-and-feel of left aligned labels and right aligned values by way of an HStack and Spacer. Have I overlooked a way to style a Form or LabeledContent that would provide the results I'm looking for?
0
0
64
2w
SwiftUI TextField.accessibilityIdentifier is not propagated to the underlying UITextField instance.
When applying the .accessibilityIdentifier(_:) modifier to a SwiftUI TextField, the identifier is correctly added to the SwiftUI Accessibility Tree (visible in Accessibility Inspector), but it is not assigned to the accessibilityIdentifier property of the underlying UITextField instance. This causes issues for developers who monitor global notifications, such as UITextField.textDidChangeNotification. When a notification is received, the object (the UITextField) has a nil identifier, making it impossible to programmatically determine which specific text field triggered the event. Steps to Reproduce: Create a SwiftUI view containing a TextField. Apply .accessibilityIdentifier("TargetTextField") to that TextField. Set up an observer (via NotificationCenter or onReceive) for UITextField.textDidChangeNotification. Run the app and type into the text field. Inspect the accessibilityIdentifier property of the UITextField object provided by the notification. Expected Result: The UITextField.accessibilityIdentifier should be "TargetTextField". Actual Result: The UITextField.accessibilityIdentifier is nil.
1
0
235
3w
Tapping a .searchSuggestions item inside a NavigationStack dismisses the search controller
Since iOS26, I've been running into an issue with using a NavigationStack with .searchSuggestions, and using searchable with placement: .navigationBarDrawer(displayMode: .always) With this, the search is activated and search suggestions list is displayed, but tapping on the search suggestions dismisses the whole search control without doing selecting the search suggestion item. This doesn't happen on iPhone, and doesn't happen on iPadOS 18.5 or below. And removing the 'placement' argument also fixes the issue. NavigationStack { List { /// ... } .searchable( text: $searchText, tokens: $searchTokens, isPresented: $isSearchPresented, placement: .navigationBarDrawer(displayMode: .always), prompt: "Search timestamps" ) { token in Label(token.title, systemImage: token.systemImage) } .searchSuggestions { ForEach(suggestedTokens) { token in Label(token.title, systemImage: token.systemImage) .searchCompletion(token) } } .toolbar { ToolbarItem { Button(action: addItem) { Label("Add Item", systemImage: "plus") } } } } I have a test sample app with this, and created FB22639453 The same problem happens in UIKit as well, when using UISearchController with UINavigationItems' searchController.
1
0
116
3w
Combining NavigationSplitView and TabView in iOS 18
Hi folks, I've used a NavigationSplitView within one of the tabs of my app since iOS 16, but with the new styling in iOS 18 the toolbar region looks odd. In other tabs using e.g. simple stacks, the toolbar buttons are horizontally in line with the new tab picker, but with NavigationSplitView, the toolbar leaves a lot of empty space at the top (see below). Is there anything I can do to adjust this, or alternatively, continue to use the old style? Thanks!
14
3
3.1k
3w
Why doesn't .glassEffect tint render on a Menu in an iOS 26 toolbar?
This is what I am trying to achieve (from the Phone app, similar one is also in Photos) I have a standard SwiftUI Menu in a toolbar with a glass tint applied to indicate the filter is active: Menu { // …filter options } label: { Label("Filter", systemImage: "line.3.horizontal.decrease") } .glassEffect(.regular.tint(.accentColor).interactive()) The glass effect doesn't render at all, no tint. The button looks completely unstyled. If I switch the label from Label to Image, the glass renders, but as a stretched oblong pill. I have tried several other combinations too: Also in the Apple's version during hover (iPad) the highlight aligns with the tint itself (see second image above) rather than outside it like in example 3 from the list above: Is there a way to get a Menu's trigger inset tint to look as in the Phone app example?
Replies
0
Boosts
0
Views
88
Activity
1w
"any View cannot conform to View"
Hello, What is the solution to this problem, assuming that you are not supposed to use AnyView, which I hear over and over again? Given this protocol: protocol MyProtocol { associatedtype V: View var content: () -> V { get } } if I want to store a heterogenous collection of MyProtocol, let collection: [any MyProtocol], then the underlying V type of each is erased to any View, which (supposedly) does not conform to View. Is there no way to "unbox" the existential any View to get the underlying View back? That unboxing idea is something I heard in a few WWDC videos but it seems like it does not apply to View.
Topic: UI Frameworks SubTopic: SwiftUI
Replies
0
Boosts
0
Views
64
Activity
1w
SwiftUI NavigationSplitView sidebar toolbar has excessive top inset when embedded in TabView since iPadOS 26.4
I’m seeing a layout regression in SwiftUI on iPadOS 26.4 involving NavigationSplitView inside a TabView. When a NavigationSplitView is embedded in a TabView, the sidebar toolbar appears to reserve too much vertical space. There is a large vertical gap between the top edge of the sidebar and the sidebar collapse/toggle icon. It looks as if the sidebar toolbar itself has become much taller than expected. The same NavigationSplitView layout is rendered correctly when it is shown directly without being embedded in a TabView. Environment: iPadOS 26.4 or later SwiftUI iPad TabView NavigationSplitView inside one tab Expected behavior The sidebar toolbar should use its normal height, as it does when the same NavigationSplitView is shown without a surrounding TabView. The sidebar collapse/toggle icon should appear close to the top of the sidebar, without a large empty gap above it. Actual behavior When the NavigationSplitView is hosted inside a TabView, the sidebar toolbar area becomes excessively tall. A large empty space appears above the sidebar collapse/toggle icon. This only happens in the TabView setup. Rendering the same NavigationSplitView directly does not show the issue. Feedback I also filed this as Feedback Assistant report: FB22645938 Has anyone else seen this behavior since iPadOS 26.4? Is this an intentional layout change, or is there a supported way to avoid this additional top inset when using NavigationSplitView inside TabView? Reproduction import SwiftUI struct ContentView: View { enum AppTab { case first case second } @State private var selectedTab: AppTab = .first var body: some View { TabView(selection: $selectedTab) { Tab("First", systemImage: "sidebar.leading", value: .first) { NavigationSplitView { List { Section("Sidebar Content") { ForEach(1...20, id: \.self) { index in Text("Item \(index)") } } } .navigationTitle("Sidebar") .toolbar { ToolbarItem(placement: .topBarLeading) { Button { // action } label: { Image(systemName: "plus") } } } } detail: { Text("Detail") } } Tab("Second", systemImage: "doc", value: .second) { Text("Second tab") } } } }
Replies
0
Boosts
0
Views
181
Activity
2w
HSplitView resize cursor missing when split view is conditionally rendered (FB22712819)
Hey all, Ran into a fun one on macOS 26.4.1 / Xcode 26.4.1, and I think I've narrowed it down enough to be worth sharing. Symptom: HSplitView's divider drags fine, but the cursor never changes to the resize cursor on hover. Just stays as the regular arrow. The cause (in my case): the HSplitView was conditionally rendered via an outer if let: struct PlayerDetailsView: View { let theme: Theme var playerVM = PlayerViewModel.shared var body: some View { let grayscaleCM = ColorMap(table: .grayscale) ZStack { VStack(spacing: 0) { Rectangle() .fill(LinearGradient(colors: [Color.black.opacity(0.45), Color.black.opacity(0)], startPoint: .top, endPoint: .bottom)) .frame(height: 8) Spacer() Rectangle() .fill(LinearGradient(colors: [Color.black.opacity(0.45), Color.black.opacity(0)], startPoint: .bottom, endPoint: .top)) .frame(height: 8) } .allowsHitTesting(false) if let disc = playerVM.disc { HSplitView { DiscInfoView( disc: disc, theme: theme, ) .frame(minWidth: 720, alignment: .topLeading) .buttonShadow() .focusable(false) TrackListView( theme: theme, playbackSequence: playerVM.tracksInPlaybackSequence, bonusTrackStartIndex: playerVM.player.disc?.releaseMetadata?.firstBonusTrackIndex, bonusTracksTitle: playerVM.player.disc?.releaseMetadata?.bonusTracksTitle, bonusTracksDisabled: playerVM.bonusTracksDisabled, onBonusIconTap: { playerVM.player.bonusTracksDisabled.toggle() } ) .frame(minWidth: 512) .focusable(false) } } } .background( LinearGradient( colors: [ grayscaleCM.color(for: 0.23), grayscaleCM.color(for: 0.17), ], startPoint: .top, endPoint: .bottom ) ) } } The fix: move the conditional inside the HSplitView, so the split view itself is always present in the hierarchy (swap line 21 and 22 of code above): HSplitView { if let disc = playerVM.disc { DiscInfoView( disc: disc, theme: theme, ) .frame(minWidth: 720, alignment: .topLeading) .buttonShadow() .focusable(false) TrackListView( theme: theme, playbackSequence: playerVM.tracksInPlaybackSequence, bonusTrackStartIndex: playerVM.player.disc?.releaseMetadata?.firstBonusTrackIndex, bonusTracksTitle: playerVM.player.disc?.releaseMetadata?.bonusTracksTitle, bonusTracksDisabled: playerVM.bonusTracksDisabled, onBonusIconTap: { playerVM.player.bonusTracksDisabled.toggle() } ) .frame(minWidth: 512) .focusable(false) } } I asked Claude AI about it and its guess is that conditionally inserting the HSplitView causes its underlying NSSplitView to get torn down and rebuilt on view updates, and the tracking areas responsible for the resize cursor never get a chance to settle. But that would be great to have a confirmation from someone at Apple who knows what's happening under the hood. Is this a known issue or an Expected behavior? Filed as FB22712819 in case anyone wants to duplicate. I posted this in case anyone had the same very specific issue... Cheers!
Topic: UI Frameworks SubTopic: SwiftUI
Replies
0
Boosts
0
Views
125
Activity
2w
Disabling font Anti-Aliasing in a Text in SwiftUI
Hi, I'm using one ttf font that simulate a bitmap look in my app. However, macOS renders all font with anti-aliasing. On those kind of font, that introduce some artefacts. Is there a way to disable anti-aliasing or some tricks that would make like there were no anti-aliasing? Thanks.
Replies
7
Boosts
0
Views
534
Activity
2w
How can I intercept Shift+Tab in SwiftUI on macOS?
Hi everyone, I'm building a macOS SwiftUI app and I'm trying to intercept both: Tab Shift + Tab to perform custom actions (similar to how text editors indent/outdent items). Right now, plain Tab works fine, but Shift + Tab never reaches my .onKeyPress(.tab) handler. Here's what I'm currently trying: import SwiftUI struct ShiftTabNotIntercepted: View { @State private var shiftKeyPressed = false var body: some View { Text("Hello") .focusable() .onKeyPress(.tab) { print("tab pressed with shift: \(shiftKeyPressed)") return .handled } .onModifierKeysChanged(mask: .shift) { old, new in shiftKeyPressed = new.contains(.shift) } } } Behavior: Pressing Tab prints: tab pressed with shift: false Pressing Shift + Tab does nothing — .onKeyPress(.tab) never fires. I also noticed: if a sidebar is visible, Shift + Tab moves focus to the sidebar if no sidebar is visible, it still doesn't trigger the handler So it seems macOS is intercepting Shift + Tab for focus navigation before SwiftUI sees it. My goal is to fully own this keyboard behavior for a custom outline/tree editor UI. Questions: Is there a SwiftUI-native way to intercept Shift + Tab? Is .onKeyPress fundamentally unable to capture this combination? Do I need to drop down to AppKit (NSViewRepresentable, keyDown, etc.) to reliably handle it? Thanks!
Replies
1
Boosts
0
Views
150
Activity
2w
.buttonStyle(.glass) background changes abruptly between 50pt and 51pt in dark mode
[Submitted as FB22612121] A SwiftUI Button using .buttonStyle(.glass) with .buttonBorderShape(.capsule) changes its background abruptly when its size goes from 50×50 to 51×51 points in dark mode. This appears to be a threshold in opacity/material rather than a smooth size-based change. The sample shows identical buttons at 40, 50, 51, and 60 points, with a clear jump between 50 and 51. Measured RGB values shift from 19,19,19 to 30,30,30. The effect also varies with the background, which points to a material/opacity change rather than a fixed fill. ENVIRONMENT iOS 26.4.1 (23E254a) iOS 26.5 (23F5059e) REPRO STEPS Create a new iOS SwiftUI project. Replace ContentView with the sample code below. Run the app or open ContentView in SwiftUI Preview (dark mode). Observe the buttons at 40×40, 50×50, 51×51, and 60×60. Compare the 50pt and 51pt buttons. ACTUAL The background changes abruptly between 50pt and 51pt. The 51pt button uses a noticeably different opacity/material, producing a visible jump in dark mode. EXPECTED The glass background should remain visually consistent or change smoothly as size changes by 1 point. 50pt and 51pt buttons should not have a discontinuous difference. SCREENSHOT SAMPLE CODE struct ContentView: View { private let sizes: [CGFloat] = [40, 50, 51, 60] var body: some View { ScrollView { VStack(alignment: .leading, spacing: 16) { Text("Glass button dark-mode size jump") .font(.headline) Text("All buttons use .buttonStyle(.glass). Only the label frame changes.") .font(.footnote) .foregroundStyle(.secondary) ForEach(Array(sizes.enumerated()), id: \.offset) { index, size in HStack(spacing: 14) { Button { } label: { Text("\(index + 1)") .font(.system(size: size * 0.42, weight: .medium)) .frame(width: size, height: size) } .buttonStyle(.glass) .buttonBorderShape(.capsule) Text("label frame: \(Int(size)) x \(Int(size))") .font(.callout.monospacedDigit()) .foregroundStyle(.secondary) } } } .padding(24) } .preferredColorScheme(.dark) } }
Topic: UI Frameworks SubTopic: SwiftUI
Replies
1
Boosts
0
Views
208
Activity
2w
Prominent glass button in SwiftUI incorrect text style
How do you create a prominent glass button in SwiftUI? In UIKit it’s let button = UIButton(configuration: .prominentGlass()) button.configuration?.title = "Agree" I tried Button("Agree") {} .buttonStyle(.glassProminent) but the title text is white not glassified 🤨
Replies
0
Boosts
0
Views
82
Activity
2w
iOS 18.6.2 issue with "let"
I am facing an issue in SwiftUI on iOS 18.6.2 where passing a value to a destination view during navigation is not working as expected. In my implementation, I pass a billerId as a constant (let) to the destination view (BillersItemView) using NavigationLink. This approach works correctly across all previous iOS versions. However, on iOS 18.6.2, the destination view does not receive the updated value properly. Before triggering navigation, the value is correctly updated in the ViewModel, but the destination view seems to receive an incorrect or stale value, which affects further API calls and UI rendering. This pattern of passing immutable (let) values is used throughout the app and has always worked reliably, so this behavior appears inconsistent and possibly related to changes in SwiftUI navigation handling in iOS 18.6.2. Could you please confirm if this is a known issue or if there are any recommended changes or workarounds to ensure correct data passing in this scenario? It can be very likely a SwiftUI navigation state timing issue that became more visible in iOS 18.x, especially with NavigationLink(isActive:) + external @ObservedObject updates. But i need to know why this is working in others. I have attached the relevant code for your reference. import SwiftUI struct CategoryBillersView: View { @ObservedObject var billPaymentsVM: BillPaymentsViewModel @State private var goToBillerItem = false var body: some View { NavigationView { VStack { NavigationLink(isActive: $goToBillerItem) { BillersItemView( billPaymentsVM: billPaymentsVM, billerId: billPaymentsVM.selectedBillerId ) } label: { EmptyView() } Button("Go to Biller") { billPaymentsVM.selectedBillerId = 123 goToBillerItem = true } } } } } struct BillersItemView: View { @ObservedObject var billPaymentsVM: BillPaymentsViewModel let billerId: Int var body: some View { Text("Biller ID: \(billerId)") .onAppear { billPaymentsVM.fetchBiller(billerId: billerId) } } } class BillPaymentsViewModel: ObservableObject { @Published var selectedBillerId: Int = 0 }
Topic: UI Frameworks SubTopic: SwiftUI
Replies
0
Boosts
0
Views
61
Activity
2w
How to achieve this vibrant background effect on iOS?
Hi everyone, I'm trying to reproduce an effect that Apple has created for the Contacts app on iOS, iPadOS and MacOS v26.4 where the contact card is displayed with a nice material frosted background that blends well with the underlying background. I love this effect and I want to use it in my app to display different information. As you can see in the screenshot, the list rows have a frosted background (probably thinMaterial) combined with a vibrant effect that adapts to the underlying view background. Additionally, the fields labels and icons also have a nice effect. I've tried everything but I'm unable to accurately recreate this effect. I tried applying a Rectangle with a material background listRowBackground but this resulted in something different than what Apple is using (either too light, too dark, or simply not vibrant). I've even tried SwiftUIVisualEffects swift package which can apply a vibrancy effect. However the result is still not the same as the one you see in the screenshot, with the correct contrast between background and labels. Any guidance would be appreciated. Thank you 🙏🏻
Replies
4
Boosts
0
Views
400
Activity
2w
Right Way of Positioning an Always Visible Overlay on Top of Navigation Bar That Aligns With Other Navigation Items
Starting with Liquid Glass, the navigation items seem not to be vertically centered within the navigation bar. This makes it very challenging to position an overlay on top of the navigation bar so that it aligns naturally with other elements such as the back button, dismiss button, and others. We want to achieve this for a progress bar so that it remains visible regardless of which views are pushed underneath. Therefore, we cannot add it as a navigation item on each screen, as doing so would cause the progress bar to animate repeatedly as new screens are pushed onto the stack. This used to be easier pre liquid glass since navigation items were centered vertically within the navigation bar. The approach I tried to center the progress bar in the navigation bar: Get access to the top safe area insets through GeometryReader Get access to the the status bar height through UIWindowScene's statusBarManager Subtract status bar height from top safe area inset to calculate the navigation bar height Update the padding of the progress bar accordingly to make sure it is centered within the navigation bar This works, but as I mentioned, now the navigation items are not centered, and the amount of vertical offset they have seems to differ from one screen to another, making it impossible to come up with an additional padding value to align across devices. See how the navigation item looks like within the navigation bar in the view debugger (doesn't matter if it is UINavigationController or NavigationStack the behaviour is the same, also please note that the positioning is the same for a view without an explicit leading toolbar item, where the default back button is provided by the system when a view is pushed): Existing code (without any hacky solutions) to add a progress bar on top as overlay: struct ContentView: View { @State var shouldShowOverlay = false var body: some View { NavigationStack { NavigationLink("Go to View2") { View2() } .navigationBarTitleDisplayMode(.inline) .toolbar { ToolbarItem(placement: .topBarLeading) { Button { } label: { Image(systemName: "chevron.left") } } } } .overlay(alignment: .top) { ProgressView(value: 0.5) .frame(width: 200) // what to add as padding here // .padding(.top, 16.0) } } How it looks: Some additional observations for the navigation bar item here: There seems to be 4 _UINavigationBarPlatterAnimationViews in the view stack, prior to the bar button item:
 The first two seems to be fine, they both have (0, 0, 44, 44) for both frame and bounds
 The third one’s frame has height and width of 48.2, and x, y values of -2.1. The last one’s frame has 40,17 for height and width and 1.92 for x,y values. Both views have the following bounds: (0, 0, 44, 44). I also tried to access to the origin of the back bar button item so that I could calculate where the position the overlay, but that also didn't yield to something useful, not to mention it would also be a super hacky solution. So my ultimate question is, is there a clean way to position an overlay on top of the navigation bar that vertically aligns with other navigation bar items, or should we just position it elsewhere and do not mess with navigation bar anymore? Any input would be greatly appreciated.
Replies
0
Boosts
1
Views
180
Activity
2w
apply .activityBackgroundTint modifier in smartstack
On iOS 26, when using .activityBackgroundTint modifiers to change the background color in the Activity Kit, the changes do not appear to apply correctly in Smart Stack. While the color changes as expected, the background is rendered as simply transparent without a glass effect which reduces readability. The glass effect is applied only when activityBackgroundTint is not used.
Replies
0
Boosts
0
Views
220
Activity
2w
Having trouble with RawRespresentable "Expected to decode String but found a dictionary instead."
I want to use AppStorage for a custom struct I am using struct Activities { var name: String var age: Int } struct ContentView: View { @AppStorage("key") private var activities: Activities = .init(name: "Albert", age: 42) var body: some View { VStack { TextField("Activity Name", text: $activities.name) } } } The above code generates a compiler warning, recommending I add RawRepresentable conformance. So I've added it like this: extension Activities: RawRepresentable { public init?(rawValue: String) { guard let data = rawValue.data(using: .utf8) else { return nil } do { let result = try JSONDecoder().decode(Activities.self, from: data) self = result } catch { print(error) return nil } } var rawValue: String { guard let data = try? JSONEncoder().encode(self), let result = String(data: data, encoding: .utf8) else { return "{}" } return result } } This leads to a stack overflow because calling encode from rawValue calls rawValue. :-( I overcame this by declaring Codable conformance and overriding the default Encodable implementation: extension Activities: Codable { enum CodingKeys: String, CodingKey { case name case age } func encode(to encoder: any Encoder) throws { var container = encoder.container(keyedBy: CodingKeys.self) try container.encode(name, forKey: .name) try container.encode(age, forKey: .age) } } This solves the stack overflow, but now init?(rawValue: String) is failing and I'm not sure why. When I set a breakpoint in my catch block I see the following: (lldb) po error ▿ DecodingError ▿ typeMismatch : 2 elements - .0 : Swift.String ▿ .1 : Context - codingPath : 0 elements - debugDescription : "Expected to decode String but found a dictionary instead." - underlyingError : nil (lldb) po rawValue {"name":"Albert2","age":42} (lldb) po data ▿ 27 bytes - count : 27 ▿ bytes : 27 elements - 0 : 123 - 1 : 34 - 2 : 110 - 3 : 97 - 4 : 109 - 5 : 101 - 6 : 34 - 7 : 58 - 8 : 34 (truncated to save space for posting :-)
Replies
2
Boosts
0
Views
483
Activity
2w
SwiftUI Text rendering with too small height / one line missing causing unexpected text truncation on iPhone devices
FB: FB22577211 The following trivial SwiftUI Text rendering causes wrong text layout and truncated text. The text should take the required height to render the text without truncation. Adding fixedSize does also not solve this. This bug only happens on devices and not on the simulator. Confirmed with iPhone 15 and iOS 26.4.1 but my colleague used another iPhone so it’s multiple iPhone devices. import SwiftUI let txt = """ Es sollte die erste Japan-Tournee von vielen werden, kein anderes Land – abgesehen von Österreich und der Schweiz – bereisten die Berliner Philharmoniker häufiger. Wie kam es zu dem überschäumend herzlichen Empfang, der dem Orchester bei seinem ersten Gastspiel in Tokio bereitet wurde und wie wurde das Land zu einer »zweiten Heimat« für die Berliner? Ein konkreter historischer Grundstein für das hohe Ansehen klassischer Musik »made in Germany« in Japan wurde bereits im 19. Jahrhunderts gelegt: Als Teil von umfassenden gesellschaftlichen Modernisierungsmaßnahmen vergab die Regierung ab 1868 Stipendien an junge japanische Intellektuelle, damit diese an den besten internationalen Instituten studieren konnten. Berlin wurde – neben Wien – als globales Zentrum der Musik betrachtet, und so erhielten viele japanische Studierende um die Jahrhundertwende die Gelegenheit, von Komponisten wie etwa Max Bruch zu lernen. Zurück in der Heimat, teilten sie ihre Begeisterung für die europäische Kunstmusik sowie das Wissen um die instrumentale und kompositorische Praxis der klassisch-romantischen Tradition. """ struct ContentView: View { var body: some View { VStack { Text(txt) } .padding(.leading, 20) .padding(.trailing, 20) .frame(maxWidth: .infinity) } } This is also enough: Text(txt) .padding(.horizontal, 20) .fixedSize(horizontal: false, vertical: true) Expected: Text is rendered without truncation / ellipsis. Actual: Text is rendered with too small height / missing one line so it’s truncated / with ellipsis.
Replies
10
Boosts
0
Views
601
Activity
2w
tabViewBottomAccessory does not inherit tab bar vibrancy / foregroundStyle behavior
Hi, I’m experimenting with the new tabViewBottomAccessory API and I’m running into an inconsistency with how colors are handled compared to the native tab bar items. Context When using a TabView, the system tab bar automatically adapts its foreground color (icons and labels) based on the background content (light/dark, images, etc.). This is the expected “vibrancy” behavior. However, when adding content via .tabViewBottomAccessory, the foreground color does not seem to follow the same logic. Minimal example : import SwiftUI struct ContentView: View { var body: some View { TabView { Tab("Home", systemImage: "house") { Text("Home") .frame(maxWidth: .infinity, maxHeight: .infinity) .ignoresSafeArea() } Tab("New", systemImage: "squareshape.split.2x2") { Text("New") .frame(maxWidth: .infinity, maxHeight: .infinity) .foregroundStyle(.white) .background(Color.black) .ignoresSafeArea() } } .tabViewBottomAccessory { HStack { Image(systemName: "command.square") Text("Message test") Spacer() Image(systemName: "play.fill") } .padding(.horizontal, 20) .foregroundStyle(.primary) } } } Observed behavior Tab bar icons and labels correctly switch between dark and light depending on the background. Content inside .tabViewBottomAccessory remains black, even when .foregroundStyle(.primary) is used. Expected behavior I would expect .tabViewBottomAccessory content to: Either inherit the same vibrancy/foreground adaptation as the tab bar items Or have a documented way to match that behavior I want to reuse the Apple Music Navigation
Topic: UI Frameworks SubTopic: SwiftUI
Replies
0
Boosts
0
Views
85
Activity
2w
SwiftUI TabView(.sidebarAdaptable) does not reliably animate content resize when switching between sidebar and top tab bar on iPad
Hi everyone, I’m building an iPad app in SwiftUI using the adaptive tab navigation pattern: Tab(value: .overview) { OverviewView() } label: { Label("Overview", systemImage: "archivebox") } Tab(value: .gallery) { GalleryView() } label: { Label("Gallery", systemImage: "shippingbox") } Tab(value: .canvas) { CanvasView() } label: { Label("Canvas", systemImage: "rectangle") } Tab(value: .record) { recordView } label: { Label("Record", systemImage: "plus") } } .tabViewStyle(.sidebarAdaptable) .tabViewCustomization($tabCustomization) The issue is that when the adaptive tab bar switches between the sidebar placement and the top bar placement on iPad, the content area resize animation is unreliable. The system navigation chrome changes correctly, but some tab contents jump directly to their final width instead of smoothly animating with the sidebar/top bar transition. Interestingly, one of my record views appears to animate consistently, so it seems the system transition itself is possible, but some view hierarchy or navigation structure may be preventing the animation in other tabs. Each major tab currently owns its own NavigationStack. For example, OverviewView, GalleryView, and CanvasView each have a NavigationStack as their root view. The Record tab conditionally shows different recording views, and one of those views also contains its own NavigationStack. I have already tried several approaches, but none solved the issue reliably: Observing @Environment(.tabBarPlacement) and adding .animation(..., value:) Reporting tabBarPlacement upward using a PreferenceKey and wrapping the update in withAnimation Wrapping tab contents in GeometryReader or other outer layout containers Temporarily removing .tabViewCustomization($tabCustomization) and .customizationID(...) Reducing the implementation to the simplest documented TabView(selection:) + Tab(...) + .tabViewStyle(.sidebarAdaptable) structure Some of these attempts actually made the animation behavior worse, so I reverted them. My questions are: 1.Is the content area expected to animate automatically when TabView(.sidebarAdaptable) changes between sidebar and top bar placement on iPad? 2.Is it recommended for each tab to own its own NavigationStack in this setup? 3.Could tabViewCustomization(:) or customizationID(:) affect the sidebar/top bar transition animation? 4.Is there an official SwiftUI pattern for preserving the system animation transaction during this adaptive tab bar placement change? 5.If this is expected behavior or a current limitation, what structure would Apple recommend for this kind of iPad navigation? Thanks in advance!
Topic: UI Frameworks SubTopic: SwiftUI
Replies
0
Boosts
0
Views
99
Activity
2w
Styling LabeledContent inside a Form on macOS?
On macOS 26, the Label part of a LabeledContent control and the Section.header part of a Section do not seem to honour view modifiers like .controlSize(.small) when used inside a Form with .formStyle(.grouped). Is there a way to make them respect the control size? Example: Form { Section("Details") { LabeledContent("Company", value: "Apple") } } .formStyle(.grouped) .controlSize(.small) // This only effects 'Apple' This produces a view where the value "Apple" is using a smaller font size but the label and the section header are not. I've tried (I think) almost every variation I can think of in terms of creating a LabeledContent and applying .controlSize but all of them come up short. The Form appears to always override my view modifiers for the section heading and label. Example 2: Form { Section { LabeledContent { Text("Company") .controlSize(.small) // Has no effect. } label: { Text("Apple") // Correctly resized to .small. } } header: { Text("Details") .controlSize(.small) // Has no effect. } } .formStyle(.grouped) .controlSize(.small) The best I've been able to come up with is a custom LabeledContentStyle that manually applies the layout and the styling, but that requires I explicitly "recreate" the macOS look-and-feel of left aligned labels and right aligned values by way of an HStack and Spacer. Have I overlooked a way to style a Form or LabeledContent that would provide the results I'm looking for?
Replies
0
Boosts
0
Views
64
Activity
2w
SwiftUI TextField.accessibilityIdentifier is not propagated to the underlying UITextField instance.
When applying the .accessibilityIdentifier(_:) modifier to a SwiftUI TextField, the identifier is correctly added to the SwiftUI Accessibility Tree (visible in Accessibility Inspector), but it is not assigned to the accessibilityIdentifier property of the underlying UITextField instance. This causes issues for developers who monitor global notifications, such as UITextField.textDidChangeNotification. When a notification is received, the object (the UITextField) has a nil identifier, making it impossible to programmatically determine which specific text field triggered the event. Steps to Reproduce: Create a SwiftUI view containing a TextField. Apply .accessibilityIdentifier("TargetTextField") to that TextField. Set up an observer (via NotificationCenter or onReceive) for UITextField.textDidChangeNotification. Run the app and type into the text field. Inspect the accessibilityIdentifier property of the UITextField object provided by the notification. Expected Result: The UITextField.accessibilityIdentifier should be "TargetTextField". Actual Result: The UITextField.accessibilityIdentifier is nil.
Replies
1
Boosts
0
Views
235
Activity
3w
Tapping a .searchSuggestions item inside a NavigationStack dismisses the search controller
Since iOS26, I've been running into an issue with using a NavigationStack with .searchSuggestions, and using searchable with placement: .navigationBarDrawer(displayMode: .always) With this, the search is activated and search suggestions list is displayed, but tapping on the search suggestions dismisses the whole search control without doing selecting the search suggestion item. This doesn't happen on iPhone, and doesn't happen on iPadOS 18.5 or below. And removing the 'placement' argument also fixes the issue. NavigationStack { List { /// ... } .searchable( text: $searchText, tokens: $searchTokens, isPresented: $isSearchPresented, placement: .navigationBarDrawer(displayMode: .always), prompt: "Search timestamps" ) { token in Label(token.title, systemImage: token.systemImage) } .searchSuggestions { ForEach(suggestedTokens) { token in Label(token.title, systemImage: token.systemImage) .searchCompletion(token) } } .toolbar { ToolbarItem { Button(action: addItem) { Label("Add Item", systemImage: "plus") } } } } I have a test sample app with this, and created FB22639453 The same problem happens in UIKit as well, when using UISearchController with UINavigationItems' searchController.
Replies
1
Boosts
0
Views
116
Activity
3w
Combining NavigationSplitView and TabView in iOS 18
Hi folks, I've used a NavigationSplitView within one of the tabs of my app since iOS 16, but with the new styling in iOS 18 the toolbar region looks odd. In other tabs using e.g. simple stacks, the toolbar buttons are horizontally in line with the new tab picker, but with NavigationSplitView, the toolbar leaves a lot of empty space at the top (see below). Is there anything I can do to adjust this, or alternatively, continue to use the old style? Thanks!
Replies
14
Boosts
3
Views
3.1k
Activity
3w