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

Posts under SwiftUI tag

200 Posts
Sort by:

Post

Replies

Boosts

Views

Activity

TabView Alignment Issue Inside a Popover on iPadOS
I've encountered an issue when using TabView inside a Popover on iPadOS, and I wanted to see if anyone else has run into this or if there's a known workaround before I file a bug report. Issue: When placing a TabView inside a Popover on iPadOS, the tab bar is not center-aligned correctly if the popover’s arrow appears on either the leading or trailing edge. It seems that the centering calculation for the TabView includes the width of the arrow itself. If the popover arrow is on the left, the tabs inside the TabView are pushed to the left. If the popover arrow is on the right, the tabs shift toward the right. This suggests that SwiftUI is incorporating the popover arrow’s width into the alignment calculation, which results in the misalignment. Questions: Has anyone else encountered this behavior? Is there a known workaround to ensure proper centering? If this is indeed a bug, should I file a report through Feedback Assistant? Any insights would be greatly appreciated!
0
0
4
3h
ForEach with binding seems to be broken in iOS 18.3.1 and iOS 18.4
Super easy to reproduce. Swiping to delete on the last remaining item in the list causes an index out of bounds exception. If you have 2 items in your list, it will only happen when you delete the last remaining item. From my testing, this issue occurs on 18.3.1 and onward (the RC it happens). I didn't test 18.3.0 so it might happen there as well. The only workarounds I have found is to add a delay before calling my delete function: OR to comment out the Toggle. So it seems as though iOS 18.3.x added a race condition in the way the ForEach accesses the values in its binding. Another thing to note, this also happens with .swipeActions, EditMode, etc... any of the built in ways to delete an item from a list. import SwiftUI struct ContentView: View { @StateObject var viewModel = ContentViewModel() var body: some View { List { ForEach($viewModel.items) { $item in HStack { Image(systemName: "globe") .imageScale(.large) .foregroundStyle(.tint) Text($item.text.wrappedValue) Spacer() Toggle(String(""), isOn: $item.isActive) .labelsHidden() } } .onDelete(perform: delete) } } func delete(at offsets: IndexSet) { // uncomment task to make code not crash // Task { viewModel.deleteItem(at: offsets) // } } } struct MyItem: Identifiable { var id: UUID = UUID() var text: String var isActive: Bool } class ContentViewModel: ObservableObject { @Published var items: [MyItem] = [MyItem(text: "Hello, world!", isActive: false)] func deleteItem(at offset: IndexSet) { items.remove(atOffsets: offset) } }
0
1
23
4h
[Suggestion] SwiftUI convenience environment navigation functions
I've been thinking a lot about how navigation and presentation are managed in SwiftUI, and I wanted to propose an idea for a more streamlined approach using environment values. Right now, handling navigation can feel fragmented — especially when juggling default NavigationStack, modals, and tab selections. What if SwiftUI provided a set of convenience environment values for these common actions? Tabs @Environment(\.selectedTab) var selectedTab @Environment(\.selectTab) var selectTab selectedTab: Read the current tab index selectTab(index: Int): Programmatically switch tabs Stack Navigation @Environment(\.stackCount) var stackCount @Environment(\.push) var push @Environment(\.pop) var pop @Environment(\.popToRoot) var popToRoot stackCount: Read how many views are in the navigation stack push(destination: View): Push a new view onto the stack pop(last: Int = 1): Pop the last views popToRoot(): Return to the root view Modals @Environment(\.sheet) var sheet @Environment(\.fullScreenCover) var fullScreenCover @Environment(\.popover) var popover @Environment(\.dismissModal) var dismissModal sheet(view: View): Present a sheet fullScreenCover(view: View): Present a full-screen cover popover(view: View): Show a popover dismissModal(): Dismiss any presented modal Alerts & Dialogs @Environment(\.alert) var alert @Environment(\.confirmationDialog) var confirmationDialog @Environment(\.openAppSettings) var openAppSettings alert(title: String, message: String): Show an alert confirmationDialog(title: String, actions: [Button]): Show a confirmation dialog openAppSettings(): Directly open the app’s settings Why? Clean syntax: This keeps navigation code clean and centralized. Consistency: Environment values already manage other app-level concerns (color scheme, locale, etc.). Why not navigation too? Reusability: This approach is easy to adapt across different view hierarchies. Example @main struct App: App { var body: some Scene { WindowGroup { TabView { NavigationStack { ProductList() } .tabItem { ... } NavigationStack { OrderList() } .tabItem { ... } } } } } struct ProductList: View { @Environment(\.push) var push @State var products: [Product] = [] var body: some View { List(protucts) { product in Button { push(destination: ProductDetails(product: product)) } } label: { ... } } .task { ... } } } struct ProductDetails: View { ... }
3
0
18
6h
Animate layout change
I want to show a view, where the user can add or remove items shown as icons, which are sorted in two groups: squares and circles. When there are only squares, they should be shown in one row: [] [] [] When there are so many squares that they don’t fit horizontally, a (horizontal) scrollview will be used, with scroll-indicator always shown to indicate that not all squares are visible. When there are only circles, they also should be shown in one row: () () () When there are so many circles that they don’t fit horizontally, a (horizontal) scrollview will be used, with scroll-indicator always shown to indicate that not all circles are visible. When there a few squares and a few circles, they should be shown adjacent in one row: [] [] () () When there are so many squares and circles that they don’t fit horizontally, they should be shown in two rows, squares on top, circles below: [] [] [] () () () When there are either too many squares or too many circles (or both) to fit horizontally, one common (horizontal) scrollview will be used, with scroll-indicator always shown to indicate that not all items are visible. I started with ViewThatFits: (see first code block) { let squares = HStack { ForEach(model.squares, id: \.self) { square in Image(square) } } let circles = HStack { ForEach(model.circles, id: \.self) { circle in Image(circle) } } let oneLine = HStack { squares circles } let twoLines = VStack { squares circles } let scrollView = ScrollView(.horizontal) { twoLines }.scrollIndicators(.visible) ViewThatFits(in: .horizontal) { oneLine twoLines scrollView.clipped() } } While this works in general, it doesn’t animate properly. When the user adds or removes an image the model gets updated, (see second code block) withAnimation(Animation.easeIn(duration: 0.25)) { model.squares += image } and the view animates with the existing images either making space for a new appearing square/circle, or moving together to close the gap where an image disappeared. This works fine as long as ViewThatFits returns the same view. However, when adding 1 image leads to ViewThatFits switching from oneLine to twoLines, this switch is not animated. The circles jump to the new position under the squares, instead of sliding there. I searched online for a solution, but this seems to be a known problem of ViewThatFits. It doesn't animate when it switches... (tbc)
1
0
19
8h
iOS 18.1 SwiftUI popover crash
When trying to debug a mysterious app crash pointing to some layoutIfNeeded() method call, me and my QA team member reduced it to this sample app. struct ContentView: View { @State var isPresented = false var body: some View { VStack { Button { isPresented = true } label: { Text("show popover") } .popover(isPresented: $isPresented) { Text("hello world") } } .padding() } }` This code crashes on his iPad iOS 18.1.0 22B5034E with EXC_BAD_ACCESS error. It is not reproducible on simulator or on device with iOS 18.2 or iOS 17. Is this a known issue? Are there any known workarounds? I've found similar posts here https://developer.apple.com/forums/thread/769757 https://developer.apple.com/forums/thread/768544 But they are about more specific cases.
1
0
39
6h
Buttons in menu don't respect the environment value of .layoutDirection in SwiftUI
Problem Setting ".environment(.layoutDirection, .rightToLeft)" to a view programmatically won't make buttons in menu to show right to left. However, setting ".environment(.locale, .init(identifier: "he-IL"))" to a view programmatically makes buttons in menu to show Hebrew strings correctly. Development environment: Xcode 16.x, macOS 15.3.1 Target iOS: iOS 17 - iOS 18 The expected result is that the button in the menu should be displayed as an icon then a text from left to right. Code to demonstrate the problem: struct ContentView: View { var body: some View { VStack(alignment: .leading) { Text("Buttons in menu don't respect the environment value of .layoutDirection") .font(.subheadline) .padding(.bottom, 48) /// This button respects both "he-IL" of ".locale" and ".rightToLeft" of ".layoutDirection". Button { print("Button tapped") } label: { HStack { Text("Send") Image(systemName: "paperplane") } } Menu { /// This button respects "he-IL" of ".locale" but doesn't respect ".rightToLeft" of ".layoutDirection". Button { print("Button tapped") } label: { HStack { Text("Send") Image(systemName: "paperplane") } } } label: { Text("Menu") } } .padding() .environment(\.locale, .init(identifier: "he-IL")) .environment(\.layoutDirection, .rightToLeft) } }
2
0
23
5h
SwiftUI update master list from detail view
Simple master screen with list, NavigationLink to editable detail view. I want edits on the detail screen to update to the master list "cars" variable and the list UI. On the detail view, if I edit one field and exit the field, the value reverts to the original value. Why? If I edit one field, don't change focus and hit the back button. The master list updates. This is what I want, but I can only update 1 field because of problem #1. Should be able to edit all the fields. If I implement the == func in the Car struct, then no updates get saved. Why? struct Car: Hashable, Equatable { var id: UUID = UUID() var make: String var model: String var year: Int // static func == (lhs: Car, rhs: Car) -> Bool { // return lhs.id == rhs.id // } } struct ContentView: View { @State private var cars: [Car] init() { cars = [ Car(make: "Toyota", model: "Camry", year: 2020), Car(make: "Honda", model: "Civic", year: 2021), Car(make: "Ford", model: "Mustang", year: 2022), Car(make: "Chevrolet", model: "Malibu", year: 2023), Car(make: "Nissan", model: "Altima", year: 2024), Car(make: "Kia", model: "Soul", year: 2025), Car(make: "Volkswagen", model: "Jetta", year: 2026) ] } var body: some View { NavigationStack { VStack { ForEach($cars, id: \.self) { $car in NavigationLink(destination: CarDetailView(car: $car)){ Text(car.make) } } } } } } struct CarDetailView: View { @Binding var car: Car var body: some View { Form { TextField("Make", text: $car.make) TextField("Model", text: $car.model) TextField("Year", value: $car.year, format: .number) } } }
1
0
29
1d
UIKit or SwiftUI First? Exploring the Best Hybrid Approach
UIKit and SwiftUI each have their own strengths and weaknesses: UIKit: More performant (e.g., UICollectionView). SwiftUI: Easier to create shiny UI and animations. My usual approach is to base my project on UIKit and use UIHostingController whenever I need to showcase visually rich UI or animations (such as in an onboarding presentation). So far, this approach has worked well for me—it keeps the project clean while solving performance concerns effectively. However, I was wondering: Has anyone tried the opposite approach? Creating a project primarily in SwiftUI, then embedding UIKit when performance is critical. If so, what has your experience been like? Would you recommend this approach? I'm considering this for my next project but am unsure how well it would work in practice.
1
0
29
9h
@Query with Set
How do I filter data using @Query with a Set of DateComponents? I successfully saved multiple dates using a MultiDatePicker in AddView.swift. In ListView.swift, I want to retrieve all records for the current or today’s date. There are hundreds of examples using @Query with strings and dates, but I haven’t found an example of @Query using a Set of DateComponents Nothing will compile and after hundreds and hundreds of attempts, my hair is turning gray. Please, please, please help me. For example, if the current date is Tuesday, March 4 205, then I want to retrieve both records. Since both records contain Tuesday, March 4, then retrieve both records. Sorting works fine because the order by clause uses period which is a Double. Unfortunately, my syntax is incorrect and I don’t know the correct predicate syntax for @Query and a Set of DateComponents. Class Planner.swift file import SwiftUI import SwiftData 
 @Model class Planner { //var id: UUID = UUID() var grade: Double = 4.0 var kumi: Double = 4.0 var period: Double = 1.0 var dates: Set<DateComponents> = [] init( grade: Double = 4.0, kumi: Double = 4.0, period: Double = 1.0, dates: Set<DateComponents> = [] ) { self.grade = grade self.kumi = kumi self.period = period self.dates = dates 
 } } @Query Model snippet of code does not work The compile error is to use a Set of DateComponents, not just DateComponents. @Query(filter: #Predicate<Planner> { $0.dates = DateComponents(calendar: Calendar.current, year: 2025, month: 3, day: 4)}, sort: [SortDescriptor(\Planner.period)]) var planner: [Planner] ListView.swift image EditView.swift for record #1 DB Browser for SQLlite: record #1 (March 6, 2025 and March 4, 2025) 
 
 [{"isLeapMonth":false,"year":2025,"day":6,"month":3,"calendar":{"identifier":"gregorian","minimumDaysInFirstWeek":1,"current":1,"locale":{"identifier":"en_JP","current":1},"firstWeekday":1,"timeZone":{"identifier":"Asia\/Tokyo"}},"era":1},{"month":3,"year":2025,"day":4,"isLeapMonth":false,"era":1,"calendar":{"locale":{"identifier":"en_JP","current":1},"timeZone":{"identifier":"Asia\/Tokyo"},"current":1,"identifier":"gregorian","firstWeekday":1,"minimumDaysInFirstWeek":1}}]
 EditView.swift for record #2 DB Browser for SQLlite: record #2 (March 3, 2025 and March 4, 2025) 
 [{"calendar":{"minimumDaysInFirstWeek":1,"locale":{"current":1,"identifier":"en_JP"},"timeZone":{"identifier":"Asia\/Tokyo"},"firstWeekday":1,"current":1,"identifier":"gregorian"},"month":3,"day":3,"isLeapMonth":false,"year":2025,"era":1},{"year":2025,"month":3,"era":1,"day":4,"isLeapMonth":false,"calendar":{"identifier":"gregorian","current":1,"firstWeekday":1,"minimumDaysInFirstWeek":1,"timeZone":{"identifier":"Asia\/Tokyo"},"locale":{"current":1,"identifier":"en_JP"}}}]
 
 Any help is greatly appreciated.
1
0
28
1d
Scroll up and bounce back loop issue when wrapping LazyVstack within a NavigationStack
The issue I'm facing arise when using a lazyvstack within a navigationstack. I want to use the pinnedViews: .sectionHeaders feature from the lazyStack to display a section header while rendering the content with a scrollview. Below is the code i'm using and at the end I share a sample of the loop issue: struct SProjectsScreen: View { @Bindable var store: StoreOf<ProjectsFeature> @State private var searchText: String = "" @Binding var isBotTabBarHidden: Bool @Environment(\.safeArea) private var safeArea: EdgeInsets @Environment(\.screenSize) private var screenSize: CGSize @Environment(\.dismiss) var dismiss private var isLoading : Bool { store.projects.isEmpty } var body: some View { NavigationStack(path:$store.navigationPath.sending(\.setNavigationPath)) { ScrollView(.vertical){ LazyVStack(spacing:16,pinnedViews: .sectionHeaders) { Section { VStack(spacing:16) { if isLoading { ForEach(0..<5,id:\.self) { _ in ProjectItemSkeleton() } } else{ ForEach(store.projects,id:\._id) { projectItem in NavigationLink(value: projectItem) { SProjectItem(project: projectItem) .foregroundStyle(Color.theme.foreground) } .simultaneousGesture(TapGesture().onEnded({ _ in store.send(.setCurrentProjectSelected(projectItem.name)) })) } } } } header: { VStack(spacing:16) { HStack { Text("Your") Text("Projects") .fontWeight(.bold) Text("Are Here!") } .font(.title) .frame(maxWidth: .infinity,alignment: .leading) .padding(.horizontal,12) .padding(.vertical,0) HStack { SSearchField(searchValue: $searchText) Button { } label: { Image(systemName: "slider.horizontal.3") .foregroundStyle(.white) .fontWeight(.medium) .font(.system(size: 24)) .frame(width:50.66,height: 50.66) .background { Circle().fill(Color.theme.primary) } } } } .padding(.top,8) .padding(.bottom,16) .background(content: { Color.white }) } } } .scrollIndicators(.hidden) .navigationDestination(for: Project.self) { project in SFoldersScreen(project:project,isBotTabBarHidden: $isBotTabBarHidden) .toolbar(.hidden) } .padding(.horizontal,SScreenSize.hPadding) .onAppear { Task { if isLoading{ do { let projectsData = try await ProjectService.Shared.getProjects() store.send(.setProjects(projectsData)) } catch{ print("error found: ",error.localizedDescription) } } } } .refreshable { do { let projectsData = try await ProjectService.Shared.getProjects() store.send(.setProjects(projectsData)) } catch{ print("error found: ",error.localizedDescription) } } }.onChange(of: store.navigationPath, { a, b in print("Navigation path changed:", b) }) } } I'm using tca library for managing states so this is my project feature reducer: import ComposableArchitecture @Reducer struct ProjectsFeature{ @ObservableState struct State: Equatable{ var navigationPath : [Project] = [] var projects : [Project] = [ ] var currentProjectSelected : String? } enum Action{ case setNavigationPath([Project]) case setProjects([Project]) case setCurrentProjectSelected(String?) case popNavigation } var body: some ReducerOf<Self> { Reduce { state, action in switch action { case .setNavigationPath(let navigationPath): state.navigationPath = navigationPath return .none case .setProjects(let projects): state.projects = projects return .none case .setCurrentProjectSelected(let projectName): state.currentProjectSelected = projectName return .none case .popNavigation: if !state.navigationPath.isEmpty { state.navigationPath.removeLast() } state.currentProjectSelected = nil return .none } } }
1
0
23
8h
I am developing a Immersive Video App for VisionOs but I got a issue regarding app and video player window
In Vision OS app, We have two types of windows: Main App Window – This is the default window that launches when the app starts. It displays the video listings and other primary content. Immersive Space Window – This opens only when a user starts streaming or playing a video. Issue: When entering the immersive space, the main app window remains visible in front of it unless manually closed. To avoid this, I currently close the main window when transitioning to immersive space and reopen it when exiting. However, this causes the app to restart instead of resuming from its previous state. Desired Behavior: I want the main app window to retain its state and seamlessly resume from where it was before entering immersive mode, rather than restarting. Attempts & Challenges: Tried managing opacity, visibility, and state preservation, but none worked as expected. Couldn’t find a way to push the main window to the background while bringing the immersive space to the foreground. Looking for a solution to keep the main window’s state intact while transitioning between immersive and normal modes.
0
0
28
2d
Markdown openURL can not handle property url
I'm trying to render a markdown with a link using Text. If the URL of the link is a static string, then no problem. If the URL is a property, then OpenURLAction gets a string ‘%25@’. I think this may be a bug. struct ContentView: View { let url = "https://www.google.com" var body: some View { Text("[Terms of Service](\(url))") .environment(\.openURL, OpenURLAction(handler: { url in print(url) return .handled })) } }
1
0
25
3d
UI Test Cases Failing with Custom Accessibility Labels in SwiftUI
Hello Apple Developer Support, I am writing to seek assistance with an issue we are experiencing in our SwiftUI application concerning UI test cases. Our application uses accessibility labels that differ slightly from the display content to enhance VoiceOver support. However, we have encountered a problem where our UI test cases fail when the accessibility label does not match the actual display content. Currently, we are using accessibility identifiers in our tests, but they only retrieve the accessibility label, leaving us without a method to access the actual display content. This discrepancy is causing our automated tests to fail, as they cannot verify the visual content of the UI elements. We would greatly appreciate any guidance or solutions you could provide to address this issue. Specifically, we are looking for a way to ensure our UI tests can access both the accessibility label and the actual display content for verification purposes. For ex: Problem scenario - setting accessibilityLabel masks access to any displayed content If an accessibilityLabel is set on a UI element, then it seems to be no-longer possible to check/access the displayed content of that element: var body: some View { Text("AAA") .accessibilityIdentifier("textThing") .accessibilityLabel("ZZZ") // Different label from the text which is displayed in UI } // in test... func test_ThingExists() { XCTAssert(app.staticTexts["AAA"].exists) // Fails, cannot find the element XCTAssertEqual(app.staticTexts["ZZZ"].label, "AAA") // Fails - '.label' is the accessibilityLabel, not the displayed content XCTAssertEqual(app.staticTexts["ZZZ"].label, "ZZZ") // Passes, but validates the accessibility content, not the displayed content XCTAssert(app.staticTexts["textThing"].exists) // Passes, but does not check the displayed content XCTAssertEqual(app.staticTexts["textThing"].label, "AAA") // Fails - '.label' is the accessibilityLabel, not the displayed content XCTAssertEqual(app.staticTexts["textThing"].label, "ZZZ") // Passes, but validates the accessibility content, not the displayed content } element.label still only checks the accessibilityLabel. There is not, it seems, an way back to being able to check the content of the Text element directly. Thank you for your attention and support. We look forward to your valuable insights.
0
0
52
1d
RC Pro Timeline Notification Not Received in Xcode
I'm having a heck of a time getting this to work. I'm trying to add an event notification at the end of a timeline animation to trigger something in code but I'm not receiving the notification from RC Pro. I've watched that Compose Interactive 3D Content video quite a few times now and have tried many different ways. RC Pro has the correct ID names on the notifications. I'm not a programmer at all. Just a lowly 3D artist. Here is my code... import SwiftUI import RealityKit import RealityKitContent extension Notification.Name { static let button1Pressed = Notification.Name("button1pressed") static let button2Pressed = Notification.Name("button2pressed") static let button3Pressed = Notification.Name("button3pressed") } struct MainButtons: View { @State private var transitionToNextSceneForButton1 = false @State private var transitionToNextSceneForButton2 = false @State private var transitionToNextSceneForButton3 = false @Environment(AppModel.self) var appModel @Environment(\.dismissWindow) var dismissWindow // Notification publishers for each button private let button1PressedReceived = NotificationCenter.default.publisher(for: .button1Pressed) private let button2PressedReceived = NotificationCenter.default.publisher(for: .button2Pressed) private let button3PressedReceived = NotificationCenter.default.publisher(for: .button3Pressed) var body: some View { ZStack { RealityView { content in // Load your RC Pro scene that contains the 3D buttons. if let immersiveContentEntity = try? await Entity(named: "MainButtons", in: realityKitContentBundle) { content.add(immersiveContentEntity) } } // Optionally attach a gesture if you want to debug a generic tap: .gesture( TapGesture().targetedToAnyEntity().onEnded { value in print("3D Object tapped") _ = value.entity.applyTapForBehaviors() // Do not post a test notification here—rely on RC Pro timeline events. } ) } .onAppear { dismissWindow(id: "main") // Remove any test notification posting code. } // Listen for distinct button notifications. .onReceive(button1PressedReceived) { (output) in print("Button 1 pressed notification received") transitionToNextSceneForButton1 = true } .onReceive(button2PressedReceived.receive(on: DispatchQueue.main)) { _ in print("Button 2 pressed notification received") transitionToNextSceneForButton2 = true } .onReceive(button3PressedReceived.receive(on: DispatchQueue.main)) { _ in print("Button 3 pressed notification received") transitionToNextSceneForButton3 = true } // Present next scenes for each button as needed. For example, for button 1: .fullScreenCover(isPresented: $transitionToNextSceneForButton1) { FacilityTour() .environment(appModel) } // You can add additional fullScreenCover modifiers for button 2 and 3 transitions. } }
3
0
31
6d
App Tester shares crash report over TestFlight, but I get nothing.
I have an app currently in beta testing, and my primary QA person tries to send the crash log for this one particular bug: The night before, he finished testing the app on an iPhone, left the app running in the background and the phone charging. The phone went to sleep. The phone is running the latest release of iOS 18. In the morning he wakes up the phone and gets the alert that the app "*** Crashed. Do you want to share additional information with the developer?" He taps Share, but I don't get a crash log in the organizer. I've gotten other crash logs in the organizer as recently as 2 weeks ago, This one has occurred several times and always fails to produce a report. I have tried doing the same steps without seeing any crash. Any ideas? Mike
1
0
22
5d
NavigationStack inside NavigationSplitView broken animation
In tvOS when using NavigationStack inside NavigationSplitView as below: @State private var selectedItem: String? @State private var navigationPath = NavigationPath() // Track navigation state manually var body: some View { NavigationSplitView { List(selection: $selectedItem) { Button("Item 1") { selectedItem = "Detail View 1" } Button("Item 2") { selectedItem = "Detail View 2" } } } detail: { NavigationStack(path: $navigationPath) { DetailView() .navigationDestination(for: String.self) { value in Text("New Screen: \(value)") } } } } } This example completely breaks the animation inside NavigationStack while navigating between different views, using withAnimation also breaks the navigation as the old view seems to be still in stack and is shown in the new view background. I have also submitted bug report: https://feedbackassistant.apple.com/feedback/16933927
0
0
23
6d