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

SwiftUI Documentation

Post

Replies

Boosts

Views

Activity

SwiftUI Animation very Laggy on iOS 18 Release only
Dear Experts, I created a SwiftUI View (in a UIKit based project) whose objective is to display a short animation in the front of the user screen. I developed it 8 month ago in XCode 15 for iOS 17, no problems. But since iOS 18, I can observe huge lags on my animation only in Release app. The problem is not present in Debug app. I don't understand why this problem occurs, the animation is quite simple, it's just an offset deplacement. I tried many thing like: Show the animation with a UINavigationController Show the animation with a UIWindow Move the view with .position Remove the GeometryReader All other animation withAnimation and .animation Task and DispatchQueue Etc... I found that the laggy animation occurs when I set the Optimization Level for the Swift Compiler - Code Generation to Optimize for Speed [-O]. That's very strange because we had this option on Release for iOS 17 and we had no lags... I can share to you a Sample Repository with the configuration we have. https://github.com/Thibma/sample-animation-swiftui Today the only option I used is to develop this feature in UIKit but it's too bad to skip the SwiftUI opportunity. :/ If you have any ideas to resolve this, I take ! Thank you !
0
0
165
1w
Broken behavior for TipKit on iOS 18 that blocks the interface
Step to reproduce: I installed the example project on this page I opened the Popover Tip View example And clicked on the icon that should output to the console and invalidate the tip Image(systemName: "wand.and.stars") .imageScale(.large) .popoverTip(popoverTip) .onTapGesture { print("test") // Invalidate the tip when someone uses the feature. popoverTip.invalidate(reason: .actionPerformed) } On version 17 with Tip presented, when I click on the button, I immediately get the output to the console and the tip disappears. On version 18, when I click on a button, the tip just disappears, it feels like it just overlaps everything and the clicks don't go any further. If anything the project is the same as in the example, I have only lowered the minimum version to 17.4. As I understand there is a bug in iOS version 18, hence I have a question if there are ways to fix this?
0
0
109
1w
SwiftUI List .scrollPosition not working
Hi, I am trying to read in which section in a list the user is currently located and want to scroll him to a specific section. Therefore I would like to use the new .scrollPosition modifier. Best would be the ability to implement the same snapping effect from ScrollView. So I used this snippet: struct Item: Identifiable{ var id: Int static func getMany() -> [Item] { var items = [Item]() for i in 0..<100 { items.append(Item(id: i)) } return items } } struct ContentView: View { @State var items = Item.getMany() @State var scrolledID: Item.ID? var body: some View { NavigationStack { List { ForEach(items) { item in ItemView(item: item) } } .scrollTargetLayout() .scrollPosition(id: $scrolledID) .navigationTitle("Hello, \(scrolledID ?? 0)") } } } struct ItemView: View { var item: Item var body: some View { Text("Hello world, \(item)") } } Doesn't work. So I tried to place the modifiers in different places in the code to attack several different parts of the list as the "scrollTargetLayout" - but this doesn't change anything here. Isn't the List View just the Form inside a ScrollView?! This doesn't work either. If I place the Form OR List inside a ScrollView, the contents of the list aren't displayed anymore. This seems logical, because the list is a LazyVStack rendering without a height, as it doesn't know its final height. Can we fix this somehow?
2
0
131
1w
iOS Control Widget Crash
2024-12-12_15-10-54.4423_+0800-39bc42f42baee8f05378c4924bcac0ea28d49d67.crash we collect some device crash logs from the organizer window in Xcode. Thread 0 name: Thread 0 Crashed: 0 libsystem_platform.dylib 0x000000020eb8eb44 _platform_strlen + 4 1 libc++.1.dylib 0x000000019797c7f4 std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char>>::append(char const*) + 32 (string:2845) 2 libswiftCore.dylib 0x00000001859283c0 _gatherGenericParameters(swift::TargetContextDescriptor<swift::InProcess> const*, __swift::__runtime::llvm::ArrayRef<swift::MetadataOrPack>, swift::TargetMetadata<swift::InProcess> const*, __swift:... + 144 (MetadataLookup.cpp:1218) 3 libswiftCore.dylib 0x0000000185927f5c swift::TypeLookupError::TypeLookupError<_gatherGenericParameters(swift::TargetContextDescriptor<swift::InProcess> const*, __swift::__runtime::llvm::ArrayRef<swift::MetadataOrPack>, swift::TargetMet... + 76 (TypeLookupError.h:134) 4 libswiftCore.dylib 0x00000001858f9ba0 swift_getAssociatedTypeWitnessSlowImpl(swift::MetadataRequest, swift::TargetWitnessTable<swift::InProcess>*, swift::TargetMetadata<swift::InProcess> const*, swift::TargetProtocolRequirement<swift::... + 772 (Metadata.cpp:6636) 5 libswiftCore.dylib 0x00000001858f7ab4 swift_getAssociatedTypeWitness + 92 (Metadata.cpp:6702) 6 SwiftUI 0x000000018c5090d0 static ControlWidgetConfigurationAdaptor._makeWidgetConfiguration(widget:inputs:) + 152 (<stdin>:0) 7 SwiftUI 0x000000018bd69170 TupleWidgetConfiguration.MakeList.visit<A>(type:) + 1124 (TupleWidget.swift:88) 8 SwiftUI 0x000000018c42e948 TypeConformance<>.visitType<A>(visitor:) + 120 (WidgetConfiguration.swift:132) 9 SwiftUI 0x000000018bd68768 static TupleWidgetConfiguration._makeWidgetConfiguration(widget:inputs:) + 1668 (TupleWidget.swift:59) 10 SwiftUI 0x000000018c628548 closure #1 in WidgetGraph.init<A>(rootBundle:) + 1168 (WidgetGraph.swift:53)
1
0
111
1w
SimpleWatchConnectivity sample - modernizing it
Dear Experts, I have been looking at thr SimpleWatchConnectivity sample code: https://developer.apple.com/documentation/watchconnectivity/transferring-data-with-watch-connectivity There are a couple of things in there that look out of date. Firstly, it uses a WKApplicationDelegate to receive the background tasks. I believe this can probably be entirely removed, and replaced with .backgroundTask(.watchConnectivity) { ... } on the App. Is that true? What do I need something inside the { ... } there? Secondly, it is using NSNotificationCenter to send received data from the WCSessionDelegate to the SwiftUI view hierarchy. Is there a better way to do that? I have spent a while trying to work out how a WCSessionDelegate class can connect to a binding to a SwiftUI @State property, and cause the UI to update in response to received data, but I haven't made it work. Are there any newer examples of how to do this? I'm currently only trying to send some simple applicationContext state from the phone to the watch and have some views update to show the latest values. Thanks, Phil.
3
0
170
1w
navigation
I'm using xcode 16.1 with SwiftUI. I have a program that needs another screen. How can I add navigation? All the youtube videos show you how to add navigation to a new program. Is there a video that shows you how to add navigation to an existing program? Any instruction would help. Thanks
2
0
133
1w
Programmatically change TabViewCustomization for iOS 18/iPad?
I have a TabView with a TabViewCustomization var, with customizationIDs set for all tabs. I have one tab set to .defaultVisibility(.hidden, for: .tabBar, .sidebar). This works as expected; initially, that tab isn't visible in either the tabBar or sidebar; with the sidebar open, I can click Edit and toggle the visibility. So far, so good. Is there a way that I can programmatically change the visibility? For example, folks with the Admin role should see the tab by default, while those with the User role shouldn't. If this is possible, can I hide the Edit button on the sidebar so the visibility can only be changed programmatically?
3
0
123
1w
iOS 18 SwiftUI List with animation modifier has unexpected behaviour
Noticed in iOS 18 that List element with animation modifier behaves differently. Seems that on first change of the underlying State property List updates all elements and loses its scroll position even if you insert just one element. The following code reproduces the behaviour, if you run it on iOS 17 it will behave as expected, you'll see an element being added to the list with an acompanying animation. On iOS 18 you'll lose your scroll position and judging by the animation it seems to update all the other rows in the list even though only one element of the underlaying State property was inserted. After that first update, list element on iOS will behave as expected. To reproduce the issue scroll down to the ~50th element and tap on a row, compare the behaviour on iOS 17 and iOS 18. import SwiftUI struct ContentView: View { struct ViewState: Equatable { struct Value: Identifiable, Equatable { let id: String var text: String var value: Bool } let list: [Value] } @State var viewState: [ViewState.Value] = { return (0..<100).map { id in ViewState.Value( id: "\(id)", text: "Row number: \(id + 1)", value: Bool.random() ) }}() var body: some View { list(viewState) } @ViewBuilder private func list(_ list: [ViewState.Value]) -> some View { List { ForEach(list) { row in self.value(row) } } .animation(.default, value: viewState) } @ViewBuilder private func value(_ value: ViewState.Value) -> some View { Button(action: { guard let rowIndex = viewState.firstIndex(where: { $0.id == value.id }) else { return } viewState.insert(randomValue(id: rowIndex), at: rowIndex + 1) }) { VStack { Text(value.text) Text("\(value.value ? "ON" : "OFF")") .foregroundStyle(value.value ? Color.green : Color.red) } } } private func randomValue(id: Int) -> ContentView.ViewState.Value { let id = (id*100 + 1) return .init(id: "New id: \(id)", text: "Row number: \(id)", value: Bool.random()) } } Issues has already been reported using feedback assistant FB16082730
0
0
122
1w
LiveActivity UI not showing in flutter ios app
I'm implementing iOS Live Activities in my Flutter app using the live_activities package. While the activity seems to be created (I can get the activity token, and clicking the Dynamic Island opens the app), the LiveActivity UI does not show up as expected. Logs: The following errors/warnings appear in the logs: Not updating lastKnownShmemState in CFPrefsPlistSource<0x6000006bc7e0> (Domain: group.powerdock.sessionactivity, User: kCFPreferencesCurrentUser, ByHost: No, Container: (null), Contents Need Refresh: No): 34 -> 33 What Works: The activity token is created successfully. Clicking the Dynamic Island opens my app. What Does Not Work: The LiveActivity UI does not display on the lock screen or elsewhere.
1
0
125
1w
@Binding var updates only once
I have a very annoying problem editing a property of one of my model structs: the binding var (subject) property (gender) is updated only once by a selection list. The first time I use my control, all works correctly; from the second time on, nothing happens (not even an .onChange() placed for debug... it simply doesn't fire up). EVEN MORE STRANGE BEHAVIOR: The SAME control, copied inside an Apple sample projects works perfectly (Recipies Sample, downloaded from Apple Developer site). This sample project is, I guess, at least two years old, still with @ObservableObject, @Publish, ...and so on, that I converted to @Observable protocol. FINAL CHERRY ON THE CAKE: THE SAME sample Project, copied ASIS into a new Xcode projects, doesn't work anymore! It seems an error buried deep inside Xcode compiler optimizations (maybe to avoid unnecessary views redraw carried too far...). Anyway: I'm asking for help, because I'm not able to see any reason for this behavior and - just to add a bit of frustration - a working project developed with Xcode 15, without any problem (Stager, available on the App Store), reopenend with Xcode 16 acquires the same odd behavior. Any Apple developer can help? Many thanks in advace Simplified code follows (I made a new project just with the few things needed to show the case) MODEL import Foundation import SwiftUI enum Gender : String, Codable, CaseIterable, Equatable { case male = "M" case female = "F" case nonbinary = "N" case unknown = "U" var description : String { switch self { case .male : "Male" case .female : "Female" case .nonbinary : "Not binary" case .unknown : "Unknown" } } var iconName : String { "iconGender\(self.rawValue)" } } struct Subject : Identifiable, Codable, Equatable, Hashable { var id : Int var name : String var surname : String var nickName : String // Identificativo alternativo all’anagrafica var gender : Gender // Sesso del soggetto [ M | F | * ] var imageName : String { "foto" + self.nickName.replacingOccurrences(of: " ", with: "") + ".jpg" } static func == (lhs: Subject, rhs: Subject) -> Bool { return (lhs.id, lhs.nickName, lhs.surname, lhs.name) == (rhs.id, rhs.nickName, rhs.surname, rhs.name) } static func emptySubject() -> Subject { return Subject(id: -1, name: "", surname: "", nickName: "", gender: .unknown) } func hash(into hasher: inout Hasher) { hasher.combine(id) hasher.combine(nickName) hasher.combine(surname) hasher.combine(name) } } CONTROL import SwiftUI struct FormPickerGender: View { @Binding var value : Gender let isEdit : Bool @State var presentPicker : Bool = false var body: some View { HStack { Text("Gender:").foregroundStyle(.gray).italic() if isEdit { Image(systemName: "text.magnifyingglass") .foregroundStyle(.tint) .onTapGesture { presentPicker = true } } Text("\(value.description)") } .sheet(isPresented: $presentPicker, content: { PickGender(currentGender: $value) }) } } struct PickGender: View { @Environment(\.dismiss) var dismiss @Binding var currentGender : Gender var body: some View { Text("Gender selection") .font(.title2) .foregroundStyle(.tint) Button("Cancel") { dismiss() } .buttonBorderShape(.capsule) List { ForEach(Gender.allCases, id: \.self) { genderCase in HStack { Image("\(genderCase.iconName)") if currentGender == genderCase { Text(genderCase.description) .font(.title3) .foregroundStyle(.blue) } else { Text(genderCase.description) .font(.title3) } Spacer() } .onTapGesture { currentGender = genderCase dismiss() } } .listRowInsets(EdgeInsets(top: 10, leading: 50, bottom: 10, trailing: 50)) } } } struct GenderPreviewWrapper: View { @State var subject = Subject.emptySubject() var body: some View { Form { FormPickerGender(value: $subject.gender, isEdit: true) } } } #Preview { return GenderPreviewWrapper() } Just for completion... If instead of $subject.gender, I use a state variable valued with gender and then $stateGender it works, but to create a specific state var for EACH property of a structure, seems to me to nullify the concept itself of struct: why bother to foreseen properties, if you can't manage them as a whole? Probably the solution will be to create a specific CLASS object of the STRUCT object, just for edit... something like : static func <STRUCT>.getEditObject() -> classObject static func <CLASS>.getStructObject() -> structObject ...once again: why have structs?
5
0
165
1w
How can the long - press gesture act only on a certain element in a list item?
I use the effect in the picture to do the test, I want to achieve a habit of multiple punch card effect, click to complete a punch card, long press to cancel a punch card. I'm having a problem right now. I want the long press gesture to only work on the trash icon, not extend to the entire item, causing the entire item to be highlighted. What should I do about it? I tried a lot of methods, but I didn't achieve the effect.
0
0
114
1w
Position of volumetric and 2D windows on visionOS
Hi, I would like to create an app that has a volumetric window in the middle and two 2D windows on the sides. When I tried that, the 2D windows are positioned slightly below the volumetric window for some reason (image1). Looks like the base (hadle, close button, etc.) of the volumetric window is aligned with the center of the whole 2D window. I would like all the window bases to be aligned (image2). (I can of course do this manually by dragging the window down a bit with my hand, but that’s an inconvenience for my usecase.) I tried making the whole volumetric window content higher, but that did not help and the content actually went far above the 2D windows (image3). I suppose this was some design choice when creating the whole window positioning behavior on VisionOS. Am I doing something wrong? Is there a way to achieve what I want or a better way to customize the position of windows, not just 5 predefined positions in defaultWindowPlacement? Image1 - current: Image2 - what I want: Image3 - current, larger content: Code: import SwiftUI @main struct placementTestApp: App { @Environment(\.openWindow) var openWindowAction var body: some Scene { WindowGroup(id: "volume") { VolumetricWindowView() .onAppear { openWindowAction(id: "first") openWindowAction(id: "second") } } .windowStyle(.volumetric) .volumeWorldAlignment(.gravityAligned) WindowGroup(id: "first") { NormalWindowView() } .defaultWindowPlacement { _, context in if let mainWindow = context.windows.first(where: { $0.id == "volume" }) { WindowPlacement(.leading(mainWindow)) } else { WindowPlacement() } } WindowGroup(id: "second") { NormalWindowView() } .defaultWindowPlacement { _, context in if let mainWindow = context.windows.first(where: { $0.id == "volume" }) { WindowPlacement(.trailing(mainWindow)) } else { WindowPlacement() } } } }
1
0
132
1w
button is pressed when starting scrolling in iOS 18
On iOS 18, while on a modal screen, if the scrolling starts on a button, that button gets pressed, outside of a modal this doesn't reproduce, also not reproducible on older iOS versions, neither on modals or outside of them. The code to reproduce the issue: import SwiftUI struct ContentView: View { @State var presentModal = false var body: some View { Button(action: { presentModal = true }, label: { Text("open modal") }) .sheet(isPresented: $presentModal, content: { ScrollView { ForEach(0..<100, id: \.self) { index in Button(action: { print("Button \(index) tapped!") }) { Text("Button \(index)") .frame(maxWidth: .infinity) .frame(height: 100) .background(randomColor(for: index)) .padding(.horizontal) } } } }) } func randomColor(for index: Int) -> Color { let hue = Double(index % 100) / 100.0 return Color(hue: hue, saturation: 0.8, brightness: 0.8) } } #Preview { ContentView() }
1
2
127
1w
VisionKit: Improve barcode scanning accuracy
Hi all, I am developing an app that scans barcodes using VisionKit, but I am facing some difficulties. The accuracy level is not at where I hope it to be at. Changing the “qualityLevel” parameter from balanced to accurate made the barcode reading slightly better, but it is still misreading some cases. I previously implemented the same barcode scanning app with AVFoundation, and that had much better accuracy. I tested it out, and barcodes that were read correctly with AVFoundation were read incorrectly with VisionKit . Is there anyway to improve the accuracy of the barcode reading in VisionKit? Or is this something that is built in and the developer cannot change? Either way, any ideas on how to improve reading accuracy would help. Thanks in advance!
0
0
100
1w
OSLog Logger & SwiftUI
Hi, Are there any macros that can be used with Logger to automatically capture the SwiftUI function that the message originates from? Currently, I am using something similar to: Logger.misc.error("In \(#fileID), \(#function): \(error)") Currently, the #function only tells me that it originates in body... Ideally, I'd like to be able to tell if it was with an onAppear, onChange, Button, alert, etc... I realize I can manually enter this, but was wondering if there was a more automated way to capture this info. Thx,
0
0
97
1w
SwiftUI Transition System is confusing...
Hi everyone, I’m having trouble getting the correct horizontal slide transitions when navigating between multiple screens in my SwiftUI app. I have three screens (enum cases with an int assigned as index depending on the navigation order): .checkClient (index 0), .login(document: String) (index 1), and .register (index 2). My goal is: When moving forward (e.g., from .checkClient to .login, or from .login to any other with a greater index), the new screen should enter from the right (trailing) and the old one should exit to the left (leading). When going backward (from .register back to .checkClient, for example), the new screen should enter from the left (leading) and the old one should exit to the right (trailing). I’ve been using a state property isAdvancing to determine the direction of transitions (I use TCA, so my logic is in a Reducer body, my properties in a State and my views are normal SwiftUI Views): case .updateCurrentScreen(let newScreen): state.isAdvancing = newScreen.index > state.currentScreen.index state.currentScreen = newScreen return .none I tried applying .transition directly inside each case: .transition( .asymmetric( insertion: .move(edge: store.isAdvancing ? .trailing : .leading), removal: .move(edge: store.isAdvancing ? .leading : .trailing) ) ) This works correctly the first time I navigate forward. However, when I go to the .register screen and then hit back, the directions become inconsistent. Sometimes the removal happens in the wrong direction, and after returning to .checkClient, forward navigations stop working as intended. Then, I tried placing the transition at a higher level, wrapping the switch in a ZStack and using a single .transition(...) outside: ZStack { switch store.currentScreen { case .checkClient: StartView(...) case .login: LoginView(...) case .register: RegisterView(...) } } .transition( .asymmetric( insertion: .move(edge: store.isAdvancing ? .trailing : .leading), removal: .move(edge: store.isAdvancing ? .leading : .trailing) ) ) .animation(.easeInOut, value: store.currentScreen) But doing this results in some transitions reverting to a fade instead of a horizontal slide. I’ve also tried ensuring that isAdvancing updates before changing the currentScreen. Unfortunately, I still encounter inconsistent transitions when navigating back and forth between these screens. Here is my complete view logic (even though is not finished nor polished yet): var body: some View { WithPerceptionTracking { ZStack { AdaptiveSheetView( backgroundImage: Asset.AuthorizationDomain.background, hasBackButton: store.showsBackButton, isFullScreen: store.isFullScreen, backAction: { store.send(.goBack) } ) { if store.showsIATILogo { Image(asset: Asset.iatiLogo) .padding(spacing: .medium) } ZStack { switch store.currentScreen { case .checkClient: StartView(store: store.scope(state: \.startState, action: \.startAction)) case .login: if let newStore = store.scope(state: \.loginState, action: \.loginAction) { LoginView(store: newStore) } case .register: if let newStore = store.scope(state: \.registerState, action: \.registerAction) { RegisterView(store: newStore) } } } .transition( .asymmetric( insertion: .move(edge: store.isAdvancing ? .trailing : .leading), removal: .move(edge: store.isAdvancing ? .leading : .trailing) ) ) } .animation(.easeInOut, value: store.currentScreen) if store.startState.checkUser == .loading { LoadingSpinner() } PreloadView(store: store.scope(state: \.preloadState, action: \.preloadAction)) .opacity(store.preloadViewShown ? 1.0 : 0.0) .animation(.linear(duration: 0.5), value: store.preloadViewShown) .onChange(of: store.preloadViewShown) { shown in if !shown { store.send(._checkPreviousSessions) } } } } } Has anyone experienced similar issues or found a reliable pattern for achieving these “push/pop” style transitions in SwiftUI? Any guidance would be greatly appreciated! My minimum target is iOS 16, so I can not make use of TabView with paginated style for this AFAIK. Thanks in advance for any time and attention you dedicate to me 🙏🏼
1
0
173
1w
RealityKit attachments on macOS?
I'm building a SwiftUI+RealityKit app for visionOS, macOS and iOS. The main UI is a diorama-like 3D scene which is shown in orthographic projection on macOS and as a regular volume on visionOS, with some SwiftUI buttons, labels and controls above and below the RealityView. Now I want to add UI that is positioned relative to some 3D elements in the RealityView, such as a billboarded name label over characters with a "show details" button and such. However, it seems the whole RealityView Attachments API is visionOS only? The types don't even exist on macOS. Why is it visionOS only? And how would I overlay SwiftUI elements over a RealityView using SwiftUI code on macOS if not with attachments?
1
0
175
1w
Mac: TabView sidebar style does not select Tabs from label or image, only whitespace
On MacOS when TabView is in sidebarAdaptable mode: Clicking the Tab directly on the text of its label, or its systemImage, does not actually select the Tab. The only way to select the Tab is to click whitespace around the text, for example to the right side of the text. iOS has behavior better – you can click the text or image to select the Tab. This behavior is really bizarre and not user-friendly. I'm surprised it could even ship like this. Tabs are actually unusable in sidebarAdaptable because users should not have to be explained to that they need to click on whitespace. Am I missing something? Seems almost too strange to be a bug.
0
0
88
1w
Suppressing contextual menu on AVPlayerView in SwiftUI app
My app plays videos. At first I used SwiftUI’s VideoPlayer, but that didn't give me enough control over the underlying AVPlayerView, so I created my own NSViewRepresentable. That works well, and I can adjust the AVPlayerView as I see fit. But it seems to have a contextual menu that still appears instead of the one I try to apply using SwiftUI. If I put a non-opaque color over the AVPlayerView in a ZStack, I'm able to then add a .contextMenu that works, but only if the color is non-opaque (e.g. Color(red: 0, green: 0, blue: 0, opacity: 0.00001)). This feels like a pretty hacky solution, and doesn’t work if I set opacity: to 0. Is there a better way to keep AVPlayerView from handling events? It also gets scroll events (which scrubs through the movie) that I'd like to suppress.
0
0
86
1w