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 !
SwiftUI
RSS for tagProvide views, controls, and layout structures for declaring your app's user interface using SwiftUI.
Post
Replies
Boosts
Views
Activity
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?
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?
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)
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.
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
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?
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
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.
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?
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.
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()
}
}
}
}
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()
}
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!
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,
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 🙏🏼
crash log
Anyone can understand the log? I really don't understand.
Please see the attachment crash and help to resolve it, thanks very much.
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?
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.
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.