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

SwiftUI Documentation

Post

Replies

Boosts

Views

Activity

Picker with icon button
I'm recreating the sleep timer from the Podcasts app. How can I display an icon for the picker instead of the current selection? This doesn't work: Picker("Sleep Timer", systemImage: "moon.zzz.fill", selection: $sleepTimerDuration) { Text("Off").tag(0) Text("5 Minutes").tag(5) Text("10 Minutes").tag(10) Text("15 Minutes").tag(15) Text("30 Minutes").tag(30) Text("45 Minutes").tag(45) Text("1 Hour").tag(60) } Do I need to drop down to UIKit for this?
1
0
96
3d
SwiftUI List misaligned with title bar.
Hello! I am making an app in SwiftUI and find it hard to make good-looking UIs with SwiftUI when using the List. When having a big navigation bar, the list appears misaligned with the title. This is a preview within Xcode. Don't know if that changes anything 🤷. Below is the code. I should note I am using Xcode 16 beta 3. // // SwiftUIView.swift // import SwiftUI struct SwiftUIView: View { struct D { var id: Int var name: String var identifier: String } let items: [(Int, D)] = [ (0, D(id: 0, name: "Test One", identifier: "one.example.test")), (1, D(id: 1, name: "Test One", identifier: "two.example.test")), (2, D(id: 2, name: "Test One", identifier: "three.example.test")), (3, D(id: 3, name: "Test One", identifier: "four.example.test")) ] var body: some View { NavigationStack { List(items, id: \.1.id) { idx, d in VStack(alignment: .leading) { Text(d.name) .bold() Text(d.identifier) } } .navigationTitle("Hello Title") } } } #Preview { SwiftUIView() }
2
0
122
3d
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!
2
0
100
3d
iPadOS 18 TabView / NavigationSplitView title
I have a TabView with individual tabs containing NavigationSplitViews. On iPadOS 18, when moving the new UI into a sidebar, the title of the first column in the current split view randomly spins its way in and out of view. Is this just a beta bug, or am I doing something wrong? Hard to convey without a recording, but hopefully the screenshots will show what I mean. Thanks.
1
0
66
3d
Collapsing NavigationStack When NavigationSplitView is Backgrounded on iPadOS 17.x
I'm pursuing a design that necessitates a dual app architecture — using a NavigationStack for compact-sized screens, and a NavigationSplitView for regular-sized screens. I've encountered what might be a bug in NavigationSplitView on iPadOS 17.x. Or perhaps it's a mistake in my code. When navigating into nested views (relying on NavigationPath), everything works fine... until I background the app on iPad. At this point, the navigation stack appears to collapse in the NavigationSplitView detail area — merging the parent and child views. Adding to the mystery... I can reproduce this bug on iPadOS 17.x. But the problem goes away when running on iPadOS 18.x beta. Key questions: Is there a problem in my code? Should I file a feedback with the Apple SwiftUI team? If iPadOS 18.x fixes this bug, can I expect a SwiftUI fix to be back-ported to 17.x or earlier? Steps to reproduce: Run my sample code on iPadOS simulator. Navigate to select a color, and then a shape. Put the app into the background (e.g., go to Home Screen). Return to app. What you can expect: When running on iPadOS 17.x, you'll see that the two most recent views in the stack have merged (meaning the title has changed, and the "back" button has disappeared). On iPadOS 18.x, you'll see that everything is working fine (title isn't changed, and back button remains available).
3
0
141
4d
SwiftUI Chart SectorMark Flips Pie Selection On User Input???
Confused as to why the Chart flips with each user input. The console is also output unique id for each slice which was not my intention. Not sure if the unique .id is the culprit behind the flip. selectedCount changed to: Optional(3) Selected slice: Optional(App.EmojiUsage(id: 69090646-0D0A-4FE8-86EC-4103608DC3F7, emojiTab: App.emojiTab.sad, count: 1)) Scheduling reset task to run in 2 seconds Resetting selected slice and count selectedCount changed to: Optional(1) Selected slice: Optional(App.EmojiUsage(id: DE4A76D1-CC57-4FA0-A261-9AD1A6E28F95, emojiTab: App.emojiTab.happy, count: 2)) Scheduling reset task to run in 2 seconds Resetting selected slice and count selectedCount changed to: Optional(3) Selected slice: Optional(App.EmojiUsage(id: 5052F8EA-2582-4E72-A61D-01FCCDF3DB03, emojiTab: App.emojiTab.sad, count: 1)) Scheduling reset task to run in 2 seconds Resetting selected slice and count selectedCount changed to: Optional(0) Selected slice: Optional(App.EmojiUsage(id: 5C1AB577-6CFC-4BA8-A9DF-30822EF79B91, emojiTab: App.emojiTab.happy, count: 2)) Scheduling reset task to run in 2 seconds @Model class AppModel { var id: String var journalEntry: String var date: Date var emojiTab: emojiTab init(journalEntry: String, date: Date, emojiTab: emojiTab) { self.id = UUID().uuidString self.journalEntry = journalEntry self.date = date self.emojiTab = emojiTab } } struct EmojiPrompt: Identifiable { var id = UUID() var icon: RiveViewModel var emojitab: emojiTab var title: String } enum emojiTab: String, Codable, Plottable { case happy case sad case sleep var primitivePlottable: Double { switch self { case .sleep: return 0.0 case .happy: return 1.0 case .sad: return 2.0 } } } var emojiPrompt = [ EmojiPrompt( icon: RiveViewModel( fileName: "app", stateMachineName: "happyBtnSM", artboardName: "happyBtn" ), emojitab: .happy, title: "Happy 1" ), EmojiPrompt( icon: RiveViewModel( fileName: "app", stateMachineName: "sadBtnSM", artboardName: "sadBtn" ), emojitab: .sad, title: "Sad 2" ), EmojiPrompt( icon: RiveViewModel( fileName: "app", stateMachineName: "happyBtnSM", artboardName: "happyBtn" ), emojitab: .sleep, title: "Sleep" ) ] import SwiftUI import SwiftData import RiveRuntime import Charts struct SectorChartView: View { @Environment(\.modelContext) private var context: ModelContext @Binding var selectedEmojiUsage: EmojiUsage? @State private var selectedCount: Int? @Binding var selectedSlice: EmojiUsage? @State private var resetTask: DispatchWorkItem? // State variable for the reset task var emojiUsageData: [EmojiUsage] var resetDelay: TimeInterval = 2.0 // Adjustable delay for reset var body: some View { ZStack { Chart { ForEach(emojiUsageData) { data in SectorMark( angle: .value("Count", data.count), innerRadius: .ratio(0.70), outerRadius: selectedSlice?.emojiTab == data.emojiTab ? .ratio(1.0) : .ratio(0.75), angularInset: 1.5 ) .cornerRadius(4) .foregroundStyle(by: .value("Emoji", data.emojiTab.rawValue.capitalized)) } } .chartAngleSelection(value: $selectedCount) .chartBackground { chartProxy in GeometryReader { geo in let frame = geo[chartProxy.plotFrame!] VStack { if let selectedEmojiUsage = selectedEmojiUsage { RiveViewModel(fileName: "app", stateMachineName: "\(selectedEmojiUsage.emojiTab.rawValue)BtnSM", artboardName: "\(selectedEmojiUsage.emojiTab.rawValue)Btn") .view() .frame(width: 120, height: 120) .id(selectedEmojiUsage.emojiTab.rawValue) // Force re-render when the emojiTab changes } else { RiveViewModel(fileName: "app", stateMachineName: "sleepBtnSM", artboardName: "sleepBtn") .view() .frame(width: 120, height: 120) .id("sleep") // Force re-render when default state } } .position(x: frame.midX, y: frame.midY) } } } .onChange(of: selectedCount) { oldValue, newValue in // Ensure reset task is only scheduled if there is a valid new value guard newValue != nil else { return } resetTask?.cancel() // Cancel any existing reset task print("selectedCount changed to: \(String(describing: newValue))") if let newValue = newValue { withAnimation { getSelectedSlice(value: newValue) } let task = DispatchWorkItem { withAnimation(.easeIn) { print("Resetting selected slice and count") self.selectedSlice = nil self.selectedCount = nil self.selectedEmojiUsage = nil } } resetTask = task print("Scheduling reset task to run in 2 seconds") DispatchQueue.main.asyncAfter(deadline: .now() + resetDelay, execute: task) // Schedule reset after specified delay } } .frame(width: 250, height: 250) } private func getSelectedSlice(value: Int) { var cumulativeTotal = 0 _ = emojiUsageData.first { emojiRange in cumulativeTotal += emojiRange.count if value <= cumulativeTotal { selectedSlice = emojiRange selectedEmojiUsage = emojiRange print("Selected slice: \(String(describing: selectedSlice))") return true } return false } } } var emojiUsageData: [EmojiUsage] { let groupedEntries = Dictionary(grouping: entries, by: { $0.emojiTab }) return groupedEntries.map { (key, value) in EmojiUsage(emojiTab: key, count: value.count) } } struct EmojiUsage: Identifiable { var id = UUID() var emojiTab: emojiTab var count: Int }
1
0
88
4d
NavigationSplitView TabView Toolbar Clash
I would like to create a master-detail view inside the Settings screen for my Mac app. I am trying to use a NavigationSplitView nested inside the top-level Settings TabView. (Reduced code below). However, the sidebar of the NavigationSplitView interferes with the TabView - the TabView appears to be in the detail of the NavigationSplitView even though it is its parent. I have seen others having the reverse issues with TabViews in NavigationSplitViews. Is this a known bug please? struct SettingsView: View { var body: some View { TabView { GeneralSettingsView() .tabItem { Label("General", systemImage: "gear") } .tag(SettingsSection.general) TypesView() .tabItem { Label("Types", systemImage: "star") } .tag(SettingsSection.types) } .frame(width: 375, height: 150) } } struct TypesView: View { @Environment(\.modelContext) private var modelContext @Query private var types: [ItemType] @State private var selectedType: ItemType? var body: some View { NavigationSplitView { List { ForEach(types) { type in NavigationLink { TypeView(type: type) } label: { Text(type.name) } } } } detail: { Text("Select a Type") } } }
4
0
105
4d
Text Above List w/ VStack Appears as View's Title
I am curious about the fact that the Text above the VStack is shown as a title to the view. I didn't know one could place Text above a VStack without another VStack. Here's the partial code showing the situation. @State private var results = [Result]() var body: some View { Text("Songs of Al Di Meola on iTunes") .font(.title3) .fontWeight(.bold) List(results, id: \.trackId) { item in VStack(alignment: .leading) { Text(item.trackName) .font(.headline) Text(item.collectionName) } } .task { await loadData() } } See picture for details.
0
0
78
4d
How to show scroll bars on a Swift Chart for macOS?
(I'm using macOS 14.5 and Xcode 15.4) I have a Swift Chart on macOS that needs to scroll horizontally. Simplified version: Chart(dataPoints) { data in LineMark(x: .value("X Axis", data.x), y: .value("Y Axis", data.y)) } .chartScrollableAxes(.horizontal) .chartXVisibleDomain(length: 10) The above code works fine, except that it does not show scroll bars. On a Mac with no trackpad, this means there's no mechanism to scroll the chart. On my MacBook Pro with a trackpad, I can scroll the chart with a 2-finger swipe gesture, but there are no transient scroll bars to show the relative size of the visible part of the chart. How do I add visible scroll bars to the chart so that I can scroll on Macs with no trackpad?
0
0
68
4d
ControlConfigurationIntent won't open the app despite setting openAppWhenRun = true
I am working on building Control widgets for our app and have noticed that openAppWhenRun doesn't seem to work for any ControlConfigurationIntent. When attaching the debugger to the widget extension in a sample project, I see the following error: Unknown NSError The operation couldn’t be completed. (LNActionExecutorErrorDomain error 2018.) This is reproducible as of Xcode 16.0 Beta 2 and Beta 3. I have noted that using an OpenIntent, with a parameter called target that conforms to AppEnum seems to open the app properly, but if I use that workaround, adding any additional parameters to the OpenIntent seems to break things again. Are others seeing this issue? I have feedback FB14357691. Here's some sample code below to reproduce: var body: some ControlWidgetConfiguration { AppIntentControlConfiguration(kind: "Open Any Screen", intent: OpenAppScreenIntent.self) { template in ControlWidgetButton(action: template) { Label { Text("Open App") } icon: { Image(systemName: "calendar") } }.tint(.red) } } } enum AppScreen: CaseIterable { case calendar case campus case search var title: String { switch self { case .calendar: "Calendar" case .campus: "Campus" case .search: "Search" } } } struct OpenAppScreenIntent: ControlConfigurationIntent { static var title: LocalizedStringResource = "Open app to a screen" static var description = IntentDescription("Opens the app.") /// The app should open regardless of what happens here static let openAppWhenRun: Bool = true @Parameter(title: "Screen", optionsProvider: OsuScreenOptionsProvider()) var screen: String? struct OsuScreenOptionsProvider: DynamicOptionsProvider { func results() async throws -> ItemCollection<String> { var screenTitles: [String] = [] for screen in AppScreen.allCases { async let title = screen.title await screenTitles.append(title) } return ItemCollection { ItemSection(items: screenTitles.map { IntentItem($0)}) } } func defaultResult() async -> String? { return "Campus" } } @MainActor func perform() async throws -> some IntentResult { #warning("The app should open regardless of what happens in this method, but it doesn't") return .result() } }
5
0
124
4d
Sheets no longer open when button is tapped while popover is visible
I have an extremely simple SwiftUI View with two buttons. One displays a sheet, the other one a popover. struct ContentView: View { @State private var showPopover = false @State private var showSheet = false var body: some View { VStack { Button("Popover") { showPopover = true } .popover(isPresented: $showPopover, content: { Text("Popover content") }) Spacer() Button("Sheet") { showSheet = true } } .padding() .sheet(isPresented: $showSheet) { Text("Lorem Ipsum") } } } On iPadOS, when the Popover is visible and the "Sheet" Button (that looks disabled but is not) is pressed, nothing happens and I get the following log: Attempt to present <TtGC7SwiftUI29PresentationHostingControllerVS_7AnyView: 0x14508c600> on <TtGC7SwiftUI19UIHostingControllerGVS_15ModifiedContentVS_7AnyViewVS_12RootModifier_: 0x14501fe00> (from <TtGC7SwiftUI19UIHostingControllerGVS_15ModifiedContentVS_7AnyViewVS_12RootModifier_: 0x14501fe00>) which is already presenting <TtGC7SwiftUI29PresentationHostingControllerVS_7AnyView: 0x140023e00>. What's even worse is, the "Sheet" Button is now in a broken state and no longer works at all. Is there a way to fix this or am I right in assuming this is a bug?
5
4
161
4d
Binding a constant at init triggers View refresh
Greetings, Context Let's imagine 2 possible root Views: House and Castle. They can both present a Room view and this room view can show a Bed view. Let's also assume, for the sake of the example, that I want to pass the "$sheet" (Identifiable enum) from either House or Castle - which are 2 different enums - all the way to Bed, so that Bed can dismiss back to rootView. So I use a Binding. Visually, the UI flow is House --> \ Room --> Bed Castle --> / In RoomView and BedView, I expected to receive either a HouseSheet or a CastleSheet. So by receiving one at init, I set to a constant nil the other. For example, if I open a RoomView (or BedView) from a HouseView, the code would be init(parentHouseSheet: Binding<HouseSheet?>) { self._parentHouseSheet = parentHouseSheet self._parentCastleSheet = .constant(nil) self.from = .house } init(parentCastleSheet: Binding<CastleSheet?>) { self._parentHouseSheet = .constant(nil) self._parentCastleSheet = parentCastleSheet self.from = .castle } Problem My problem now is that the .constant(nil) appears to change and triggers a refresh! By using a simple Self._printChanges() I get the following when I navigate to a BedView (from a House origin!). RoomView: _parentCastleSheet changed. // Why? It's a binded constant and I'm not even touching RoomView at all. BedView: @self, @identity, _parentCastleSheet changed. BedView: @self, _parentCastleSheet changed. // Same why? Full code // House & Castle enum BuildingOrigin: String { case house case castle } enum HouseSheet: String, Hashable, Identifiable { case room var id: String { return self.rawValue } } enum CastleSheet: String, Hashable, Identifiable { case room var id: String { return self.rawValue } } // I only show HouseView for this example. struct HouseView: View { @State private var sheet: HouseSheet? var body: some View { let _ = Self._printChanges() VStack { Button("Open Room (Sheet)") { self.sheet = .room } } .padding() .sheet(item: $sheet) { sheet in switch sheet { case .room: RoomView(houseSheet: $sheet) } } } } // Room enum RoomViewDestination: String, Hashable { case bed } struct RoomView: View { @State private var path = NavigationPath() @Binding var parentHouseSheet: HouseSheet? @Binding var parentCastleSheet: CastleSheet? let from: BuildingOrigin init(houseSheet: Binding<HouseSheet?>) { self._parentHouseSheet = houseSheet self._parentCastleSheet = .constant(nil) self.from = .house } init(castleSheet: Binding<CastleSheet?>) { self._parentHouseSheet = .constant(nil) self._parentCastleSheet = castleSheet self.from = .castle } var body: some View { let _ = Self._printChanges() NavigationStack(path: $path) { List { NavigationLink(value: RoomViewDestination.bed) { Text("Open Bed (Navigation)") } } .navigationDestination(for: RoomViewDestination.self) { destination in switch destination { case .bed: switch self.from { case .house: BedView(parentHouseSheet: $parentHouseSheet) case .castle: BedView(parentCastleSheet: $parentCastleSheet) } } } } } } // Bed struct BedView: View { @Binding var parentHouseSheet: HouseSheet? @Binding var parentCastleSheet: CastleSheet? let from: BuildingOrigin init(parentHouseSheet: Binding<HouseSheet?>) { self._parentHouseSheet = parentHouseSheet self._parentCastleSheet = .constant(nil) self.from = .house } init(parentCastleSheet: Binding<CastleSheet?>) { self._parentHouseSheet = .constant(nil) self._parentCastleSheet = parentCastleSheet self.from = .castle } var body: some View { let _ = Self._printChanges() Text("The \(from.rawValue) has a nice bed.") } }
0
0
47
4d
TabItem Not Respected In TabView
Hello, I'm a new programmer here, so this may be an error on my part, however I have tried my best to research the issue and believe I may have discover a bug. I have a set of tabItems inside of a TabView using a variable to track the selected tab called selectedIndex. I have added in a text view to watch the selected tab. This works correctly in the canvas and in a simulator, however whenever I build this on an iOS Device or for my Mac the selectedIndex does not change when selecting tabs like it does in the canvas and simulator. Instead it just stays at the default 0. Any assistance would be great. :-) import SwiftUI struct ContentView: View { @State private var selectedIndex = 0 var body: some View { Text("\(selectedIndex)") TabView(selection: $selectedIndex) { FilteredApplicantListView() .tabItem { Label("Applicant Processor", systemImage: "person.3.sequence.fill") } .tag(0) QuickFinancials() .tabItem { Label("Quick Financials", systemImage: "dollarsign.gauge.chart.leftthird.topthird.rightthird") } .tag(1) MoveInView() .tabItem { Label("Move Ins", systemImage: "figure.walk.arrival") } .tag(2) MoveOutView() .tabItem { Label("Move Outs", systemImage: "figure.walk.departure") } .tag(3) } } }
2
0
101
5d
SwiftUI view body invoked in infinite loop
I am observing infinite loop of view creation, deletion, and recreation when I move my app to background and bring back to foreground. I am clueless what is causing this repeated invocation of view body, so I tried Self._printChanges() inside the view body . But all I get is the following in console. ChildView: @ self , _dismiss changed. //<--- This is the problematic view ParentView: unchanged. //<--- This is parent view The issue has also been reported on Apple developer forums but no solution found. What are other options to debug this issue?
0
0
96
5d
Reproduce the apple macos calendar scroll layout
I am trying to recreate the apple calendar in swiftui but I have issues creating scroll layout. So I want to have: When I scroll horizontally the hours on the side have to stay fixed but the header with the day number day String and the full day events have to scroll When I scroll vertically the hours on the side have to move but the header don't For the moment I have : HStack(alignment: .top, spacing:0) { // The hours on the side LateralHours(height: geometry.size.height * 24/10) . offset(y: -offset) ScrollViewReader { proxy in ScrollView (.horizontal, showsIndicators: false) { VStack { // The day number and the full day events Header(width: width) ScrollView { LazyHStack (spacing: 0) { ForEach($loadedDays, id: \.self) { day in // The day grid with the events DayContentView( cellHeight: geometry.size.height / 10, width: width, selectedEvent: $selectedEvent, day: day, store: $store, modifiedEvent: $modifiedEvent ) } } .frame(height: 24*geometry.size.height / 10) // This code block is used to track the position of the scrollview position .background( GeometryReader { Color.clear.preference(key: ScrollOffsetPreferenceKey.self, value: -$0.frame(in: .named("scroll")).origin.y) }) .onPreferenceChange(ScrollOffsetPreferenceKey.self) { value in offset = value } } .coordinateSpace(name: "scroll") } } .scrollTargetBehavior(.viewAligned) .defaultScrollAnchor(.leading) } .scrollPosition(id: $position) .frame(alignment: .topLeading) } So the hours on the side are in none of the scrollViews they are only modified through the .offset with the vertical scrollView position. My problem is that the .offset seems to be kind of slow and my app is slowed down is there a better modifed than .offset or do you know a more efficient way to do this ?
2
0
114
5d
WidgetBundle with ControlWidget does not work on iOS 17
I'm trying to add a ControlWidget to my WidgetBundle like this: struct MyWidgets: WidgetBundle { var body: some Widget { if #available(iOSApplicationExtension 18.0, *) { LauncherControl() } MyLiveActivityWidget() HomeScreenWidget() LockScreenWidget() } This works exactly as expected on iOS 18. However on iOS 17 my app seems to have no widgets at all. The workaround described here (https://www.avanderlee.com/swiftui/variable-widgetbundle-configuration/) does not work either since WidgetBundleBuilder.buildBlock does not accept ControlWidget as an argument. What is the correct way to include a Control widget conditionally on iOS 18?
1
0
273
6d
RTL flow in SwiftUI
I have a problem in dealing with RTL language (Arabic) in SwiftUI with List and Searchable flow, also when long pressed on the search bar to prompt the options menu it is also flipped. I added the environment parameter to support right to left layout direction for the list, but when I clicks on the search bar to do the search flow the list is flipped again, Thanks in advance. var body: some View { NavigationStack { List { Section { Text("مرحبا") } } .environment(\.layoutDirection, .rightToLeft) .flipsForRightToLeftLayoutDirection(true) .navigationTitle(" جديد") .toolbar(content: { Button("اغلاق") { self.dismiss() } }) } .tint(Color.blue) .searchable(text: self.$searchText, placement: .navigationBarDrawer(displayMode: .always)) .interactiveDismissDisabled() }
1
0
109
6d
Incorrect keyboard autofill issue
I recently released my first app. I noticed that on my login screen, the keyboard on both my email TextField and my password SecureField was showing an autofill for passwords. I was setting their keyboard type, but looking into this, I noticed that there is a text content type that I should also be setting. Upon setting this, nothing changed. The only thing that does seem to change this functionality is by hiding the SecureField. I ran into a problem when I tried adding a dismiss button to the toolbar of these keyboards. I was able to find people talking about this being an iOS 17 bug. However, I have not found anyone talking about this autofill issue. Is this also a bug in iOS 17? Back when I was creating the login page for my app, I believe it was still iOS 16, and that would explain why I didn't notice it before. One more note I just ran across while testing. If I add a second identical TextField, it won't have this autofill.
0
0
108
6d
(Beta) pushWindow results duplicated window with immersive view
Here is what I have discovered: When I have window A pushes window B, and then B's onAppear dismisses A by its id. In this case, A will not appear if B later dismisses itself unless B calls open/pushWindow(id: A) However, if I then open an immersive space by A and dismiss it, there will be several B appearing depending on how many times the process I mentioned above was repeated It does make no sense using onAppear to dismiss A while we later want to reuse it, but is this feature expected?
0
0
91
6d