Has anyone else created a macOS SwiftUI app that uses a Table with a largish (~1000) number of entries? My app works OK at about 100 entries, but slows down as the number of entries increase. How slow? An instrumented test with 1219 entries shows a Hang of over 13 seconds from simply clicking/selecting an item in the table.
Instruments says the time is mostly spent in _CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION. Digging deeper I see AG::Subgraph::update(unsigned int) and descendants account for about half of the hang time.
My app is using @Observable on macOS 14 and is being tested on an M2 Max Studio.
There are other reported hangs. All seem to be in Swift/SwiftUI code.
SwiftUI
RSS for tagProvide views, controls, and layout structures for declaring your app's user interface using SwiftUI.
Post
Replies
Boosts
Views
Activity
I try to change picker text color but, it does not work.
As you see, "City" and "District"'s color are blue but, I'd like to make them white. I have tried below codes but, they do not work.
Do you know any methods for that ?
Picker("İl", selection: $selectedCity) {
ForEach(turkishCities, id: \.self) { city in
Text(city)
.foregroundColor(.white)
}
}
Picker("İlçe", selection: $selectedDistrict) {
ForEach(cityDistricts[selectedCity] ?? [], id: \.self) { district in
Text(district)
.foregroundColor(Color.white)
}
}
.onAppear {
UISegmentedControl.appearance().setTitleTextAttributes([.foregroundColor: UIColor.white], for: .normal)
}
Thank you in advance.
I'm currently evaluating Swift Charts to use in my macOS app, where I need to (potentially) display a few millions of data points, ideally all of them at one time. I want to give users the possibility to zoom in & out, so the entire range of values could be displayed at one moment.
However, starting at around 20K data points (on my computer), the Chart takes a little bit to set up, but the window resizing is laggy. The performance seems to decrease linearly (?), when dealing with 100K data points you can barely resize the window and the Chart setup/creation is noticeable enough. Dealing with 500K data points is out of the question, the app is pretty much not useable.
So I'm wondering if anybody else had a similar issue and what can be done? Is there any "magic" Swift Charts setting that could improve the performance? I have a "data decimation" algorithm, and given no choice I will use it, but somehow I was hoping for Swift Charts to gracefully handle at least 100K data points (there are other libs which do this!). Also, limiting the displayed data range is out of the question for my case, this is a crucial feature of the app.
Here's the code that I'm using, but it's the most basic one:
struct DataPoint: Identifiable {
var id: Double { Double(xValue) }
let xValue: Int
let yValue: Double
}
let dataPoints: [DataPoint] = (0..<100_000).map { DataPoint(xValue: $0, yValue: Double($0)) }
struct MyChart: View {
var body: some View {
Chart(dataPoints) { dataPoint in
PointMark(x: .value("Index", dataPoint.xValue),
y: .value("Y Value", dataPoint.yValue))
}
}
}
Some additional info, if it helps:
The Chart is included in a AppKit window via NSHostingController (in my sample project the window contains nothing but the chart)
The computer is a MacBook Pro, 2019 and is running macOS 10.14
I have my ContentView which has a Sheet that will appear when a button is pressed.
struct ContentView: View {
@EnvironmentObject private var settings: SettingsHandler
@State private var settingsView: Bool = false
var body: some View {
NavigationStack {
Button(action: {
settingsView.toggle()
}, label: {
Image(systemName: "gearshape.fill")
})
}
.preferredColorScheme(settings.darkTheme ? .dark : nil)
.sheet(isPresented: $settingsView, content: {
SettingsView()
})
}
}
Let's say the app is in light mode based on the phones theme settings. You open the SettingsView and select the toggle that will switch to dark mode. Everything changes to dark mode, including the SettingsView sheet. Then you select the same toggle to switch back and ContentView in the background changes to light theme but the sheet doesn't until you close and reopen it. I would think it would change back considering it changed to dark mode without needing to be closed.
I tried attaching an ID to the SettingsView and having it refresh when settings.darkTheme is changed, however, it doesn't seem to be doing anything. I also added the .preferredColorScheme() modifier into the SettingsView, but it did nothing. I also replaced the nil to .light, and the same issue occurred. Settings is an EnvironmentObject that I created to manage all the Settings I have.
At the moment, I'm thinking I can have the sheet just close and reopen, however, I would like for it to update properly. Any ideas?
Hi iOS member,
I have a problem to use a SwiftUI on Carplay.
The swiftUI is not refreshed when @State properties are modified.
Only UiKit views refreshs well, on Carplay.
Is it exists a way to use swiftUI views on Carplay, for example to show a speed of the user on a Map application ?
Thank you for your help.
Here an example of SwiftUI view :
public struct FakeSpeedView: View {
@State var speed: Int = 90
let timer = Timer.publish(every: 1, on: .main, in: .common).autoconnect()
public init() {}
public var body: some View {
Text("Speed \(speed)")
.onReceive(timer) { _ in
var newValue = speed + 1
if newValue > 130 {
newValue = 90
}
print("FakeSpeedView update speed \(newValue)")
speed = newValue
}
}
}
And here, the ViewController used as rootViewController for CPWindow :
class ContentViewController: UIViewController {
private var circularProgressBarView: CircularProgressBarView!
private var circularViewDuration: TimeInterval = 2
private var speedVC: UIViewController!
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
setUpSpeedView()
setUpCircularProgressBarView()
}
private func setUpSpeedView() {
speedVC = UIHostingController(rootView: FakeSpeedView())
view.addSubview(speedVC.view)
speedVC.view.translatesAutoresizingMaskIntoConstraints = false
speedVC.view.pinEdges(to: view)
addChild(speedVC)
speedVC.didMove(toParent: self)
}
private func setUpCircularProgressBarView() {
// set view
circularProgressBarView = CircularProgressBarView(frame: .zero)
// align to the center of the screen
circularProgressBarView.center = view.center
// call the animation with circularViewDuration
circularProgressBarView.progressAnimation(duration: circularViewDuration)
// add this view to the view controller
view.addSubview(circularProgressBarView)
}
}
Even if there are one-many relationship models with the cascade delete rule, SwiftData does not cascade delete items.
For example, there is one school has multiple students like the following models, and even when the school is deleted, the students in the school are not deleted. This happens when a user create a school and students and delete the school immediately.
Are there any workarounds for now?
@Model
final class School {
var name: String
@Relationship(deleteRule: .cascade, inverse: \Student.school)
var students: [Student] = []
init(name: String) {
self.name = name
}
}
@Model
final class Student {
var fullName: String
var school: School
init(fullName: String, school: School) {
self.fullName = fullName
self.school = school
}
}
Hi! I am creating a document based app and I am wondering how can I save images in my model and integrate them in the document file.
"Image" does not conform to "Persistence model" and I am sure that "Data" will be saved in the document file.
Any clue on how can I do it? Many thanks.
I've encountered a critical issue while testing my app, which is available on the App Store, on the iOS 17.2 beta (iPhone SE simulator). The app freezes and becomes unresponsive. Currently, I haven't found a workaround, which means my app is completely non-functional and untestable on iOS 17.2 beta.
The app supports iOS 15.2 and later versions, and it has been working fine from iOS 15.2 through iOS 17.1. The problem only occurs on the iOS 17.2 beta.
I have been able to reproduce the issue with the sample code provided below.
■ Test Environment:
macOS: 14.0 (23A344)
Xcode Version: 15.1 beta (15C5042i)
iPhone SE 3rd generation (simulator): iOS 17.2 (21C5029e)
■ Steps to Reproduce:
Prerequisites: Prepare an audio file, such as an m4a or mp3, and add it to the Bundle Resources.
1 Launch the sample code provided below.
2 Tap on any row's NavigationLink.
After tapping, when the program attempts to access the AVPlayer, the following log is displayed in Xcode:
CA_UISoundClient.cpp:1127 Device = 0
HALPlugInManagement.cpp:396 HALPlugInManagement::RegisterPlugIns: loading in-process plug-ins
AddInstanceForFactory: No factory registered for id <CFUUID 0x600000285600> F8BB1C28-BAE8-11D6-9C31-00039315CD46
CA_UISoundClient.cpp:1203 renderer = 0x600000011f90, synchronizer: 0x0, repeat: 0, vol: 1.00
3 Tap the Navigation's Back button at the top left.
Depending on the timing, there may be no response when pressing the button (screen). Approximately 15 seconds later, the following log is displayed, and the screen becomes responsive again as it returns to the previous view.
AQMEIO.cpp:198 timed out after 15.000s (0 0); suspension count=0 (IOSuspensions: )
MEDeviceStreamClient.cpp:467 AQME Default-InputOutput: client stopping after failed start: <CA_UISoundClientBase@0x104015d00>; running count now 0
CA_UISoundClient.cpp:293 CA_UISoundClientBase::StartPlaying: AddRunningClient failed (status = -66681).
changing items while animating can result in a corrupted navigation bar
4 If the issue does not reproduce, quit the app and then return to step 1.
In the sample code, whether the issue occurs or not may depend on the timing of screen transitions, scrolling, and tapping. (The issue might occur with a high probability if you tap 'back' during a screen transition animation.) On the production app in question, the issue occurs 100% of the time.
■ Sample code
import SwiftUI
import AVFoundation
@main
struct iOSAppHangSampleApp: App {
@StateObject var model = ContentModel()
var body: some Scene {
WindowGroup {
if #available(iOS 17, *) {
NavigationStack {
ContentView()
.environmentObject(model)
}
} else {
NavigationView {
ContentViewIOS15()
.environmentObject(model)
}.navigationViewStyle(.stack)
}
}
}
}
@MainActor
class ContentModel: ObservableObject {
private let player = AVPlayer()
@Published var playbackDuration: TimeInterval = .zero
func load() {
let url = Bundle.main.url(forResource: "YourAudioFilename", withExtension: "m4a")! // Change to your audio.
let avassetURL = AVURLAsset(url: url, options: [AVURLAssetPreferPreciseDurationAndTimingKey: true])
let avPlayerItem = AVPlayerItem(asset: avassetURL)
self.player.replaceCurrentItem(with: avPlayerItem)
self.playbackDuration = avPlayerItem.asset.duration.seconds
}
}
@available(iOS 17, *)
struct ContentView: View {
@EnvironmentObject private var model: ContentModel
private let urls: [URL] = {
(0..<50).map { URL(fileURLWithPath: "\($0)")}
}()
@State private var selected: Int?
var body: some View {
List(selection: $selected) {
ForEach(urls.indices, id: \.self) { idx in
let _ = urls[idx]
NavigationLink(value: idx) {
Text("\(idx)")
}
}
}
.navigationDestination(item: $selected) { idx in
Content3View()
.environmentObject(model)
}
}
}
@available(iOS 15, *)
struct ContentViewIOS15: View {
@EnvironmentObject var model: ContentModel
let urls: [URL] = {
(0..<50).map { URL(fileURLWithPath: "\($0)")}
}()
@State var selected: Int?
var body: some View {
List() {
ForEach(urls.indices, id: \.self) { idx in
let _ = urls[idx]
NavigationLink(tag: idx, selection: $selected) {
if selected == idx {
Content3View()
.environmentObject(model)
}
} label: {
Text("\(idx)")
}
}
}
}
}
struct Content3View: View {
@EnvironmentObject private var model: ContentModel
var body: some View {
Text("duration: \(model.playbackDuration)")
.onAppear() {
model.load()
}
}
}
■ Investigation
The sample code has been tested on the iPhone 17.0 simulator, 15.2 simulator, and an iPhone 17.1 real device, but the issue only appears on the 17.2 beta. Also, when replacing NavigationStack with NavigationView in the sample code, the issue does not seem to occur on iOS 17.2.
I'm not sure about the relationship between the back navigation and toolbar inside NavigationStack, but it might be related to the following content in the iOS 17.2 Release Notes.
Resolved Issues
* Fixed: Resolved a possible Swift access conflict crash that could occur with toolbar items. (113992797)
This issue also brings to mind the randomness associated with NavigationView / NavigationStack that I've observed.
iOS 16.4 NavigationStack Behavior Unstable https://developer.apple.com/forums/thread/727282
SwiftUI NavigationView pops back when updating observableObject https://developers.apple.com/forums/thread/693137
■ if anyone has found a workaround, please let me know.
I have not been able to confirm whether this issue occurs only on the Simulator, but it is preventing me from continuing to test on iOS 17.2 beta since the app is completely non-functional. If this is an issue with iOS 17.2 beta, I hope for a resolution before the official release of iOS 17.2.
Given that SwiftUI and modern programming idioms promote asynchronous activity, and observing a data model and reacting to changes, I wonder why it's so cumbersome in Swift at this point.
Like many, I have run up against the problem where you perform an asynchronous task (like fetching data from the network) and store the result in a published variable in an observed object. This would appear to be an extremely common scenario at this point, and indeed it's exactly the one posed in question after question you find online about this resulting error:
Publishing changes from background threads is not allowed
Then why is it done? Why aren't the changes simply published on the main thread automatically?
Because it isn't, people suggest a bunch of workarounds, like making the enclosing object a MainActor. This just creates a cascade of errors in my application; but also (and I may not be interpreting the documentation correctly) I don't want the owning object to do everything on the main thread.
So the go-to workaround appears to be wrapping every potentially problematic setting of a variable in a call to DispatchQueue.main. Talk about tedious and error-prone. Not to mention unmaintainable, since I or some future maintainer may be calling a function a level or two or three above where a published variable is actually set. And what if you decide to publish a variable that wasn't before, and now you have to run around checking every potential change to it?
Is this not a mess?
App Purchase Validation and In-App Purchase Persistence with the older StoreKit APIs is complicated. I’m curious to learn whether the new StoreKit SwiftUI views and .subscriptionStatusTask modifier simplify the process — or ideally eliminates the need to implement complex Validation and persistence logic using AppStorage, Keychain or App Receipts. Any thoughts on this?
Hi, I am trying to use SwiftUI in my project where I was using UIKit only, until now. The problem is that Preview in Xcode is not working even for very simple View with Text("Hello World"). Code is correct and project is possible to build and run. Even when I try to select real device (real iPhone) I can see Preview in my device. But preview in simulator is not working. Can someone help me with this? I am attaching diagnostic from Xcode and file from ~/Library/Logs/DiagnosticReports/
Thanks for help
xcode_preview.txt
findmylocated-2023-11-08-133122.ips.txt
Hi there, i'm currently trying to make a ChatView with SwiftUI. I've been using "inverted" ScrollView, but now I see new defaultScrollAnchor and scrollPosition methods which can make solution more kind of native and less buggy.
So, here is the snippet of my implementation:
ScrollView {
LazyVStack {
ForEach(messages) { message in
MessageView(
message: message,
actions: viewModel.messageActions
)
}
}
}
.defaultScrollAnchor(.bottom)
At this point it works as expected most of the time. But once I have a message which content doesn't fit on the screen there is the problem.
When I enter the chat for the first time all is OK:
But next times I open the chat i see only this:
But the content is scrollable, once i scroll a little bit to the top, messages appear like they just were scrolled.
I think this is the problem with LazyVStack, maybe it waits for the content top to be displayed to render item?
Here is the full code of my ChatView:
import Foundation
import SwiftUI
import SwiftData
import AlertKit
import Factory
struct ChatView: View {
@StateObject private var viewModel: ChatViewModel
@Environment(\.modelContext) private var modelContext
@Query private var messages: [ChatMessage]
@Query private var generatingMessages: [ChatMessage]
init(chat: Chat) {
_viewModel = StateObject(wrappedValue: Container.shared.chatViewModel(chat))
let chatId = chat.persistentModelID
_messages = Query(
filter: #Predicate {
$0.chat?.persistentModelID == chatId
},
sort: \.date,
animation: .spring
)
_generatingMessages = Query(
filter: #Predicate {
$0.generating && $0.chat?.persistentModelID == chatId
}
)
}
var body: some View {
VStack(spacing: 0) {
ScrollView {
LazyVStack(spacing: 0) {
ForEach(messages) { message in
MessageView(
message: message,
actions: viewModel.messageActions
)
}
}
}
.defaultScrollAnchor(.bottom)
if !messages.isEmpty { Divider() }
HStack(alignment: .bottom) {
TextField("message", text: $viewModel.text, axis: .vertical)
.padding(.vertical, 7)
.padding(.horizontal, 12)
.background(Color(.secondarySystemBackground))
.clipShape(RoundedRectangle(cornerRadius: 20))
.onSubmit {
sendMessage()
}
SendButton(enabled: generatingMessages.isEmpty) {
sendMessage()
}
.animation(.default, value: generatingMessages.count)
.padding(.vertical, 7)
}
.padding(.horizontal)
.padding(.vertical, 10)
}
.toastingErrors(with: viewModel)
.scrollDismissesKeyboard(.interactively)
.navigationTitle(viewModel.chat.title ?? "")
.navigationBarTitleDisplayMode(.inline)
}
private func sendMessage() {
if viewModel.text.isEmpty {
return
}
viewModel.startLoading()
}
}
So, is there any workaround for this issue? Or maybe I do something wrong?
I have an SwiftUI iOS app that uses TabView to display 4 different NavigationStacks. Each stack can be navigated into.
To make this app work better on iPad OS I'd like to use a NavigationSplitView with a sidebar and a detail view. The sidebar contains a menu with the 4 items that are tabs on iOS. The detail view should contain individual NavigationStacks that should retain their view paths.
After having played around with it a bit it seems to me that NavigationSplitView is not meant to be used that way. The detail view resets every time I select another menu item in the sidebar. I've tried retaining the individual navigation paths (as @States) in my root view and passing them into the individual NavigationStack when creating the detail view. However, it seems like NavigationSplitView is resetting the path whenever you switch to another menu item.
Has anybody figured this out?
On macOS tables if refreshing occasionally for example refresh data every second,
If you will try to select a row at the point the table refreshes the selection is lost
If you will try to mouse down on a row, you will see the row selected but when the table refreshes, the selection is lost
Notes:
I filled a bug already.
Wonder if there is any workaround for that.
Sample code to reproduce:
import SwiftUI
struct TableItem: Identifiable {
var id: String {
name
}
var name: String
var counter: Int
}
@Observable
class TableViewModel {
var items: [TableItem] = [
.init(name: "Row 1", counter: 10),
.init(name: "Row 2", counter: 0),
.init(name: "Row 3", counter: 56),
.init(name: "Row 4", counter: 7)
]
var selection: Set<TableItem.ID> = []
func incrementCounters() {
for index in items.indices {
items[index].counter += 1
}
}
}
struct ContentView: View {
@Bindable var viewModel = TableViewModel()
let timer = Timer.publish(every: 1, on: .main, in: .common).autoconnect()
var body: some View {
VStack {
Table(viewModel.items, selection: $viewModel.selection) {
TableColumn("name") { item in
Text(item.name)
}
.width(min: 80, ideal: 150)
TableColumn("counter") { item in
Text("\(item.counter)")
}
.width(min: 80, ideal: 150)
}
}
.padding()
.onReceive(timer) { input in
viewModel.incrementCounters()
}
}
}
I recently encountered a "potential bug" with SwiftData.
I save my model with modelContent.insert and after that I get following error when trying to delete it with modelContent.delete:
Could not cast value of type 'Swift.Optional<Any>' (0x1f5b871f8) to 'Foundation.UUID'
This I mentioning the let id: UUID field marked with @Attribute(.unique).
This build doesn't crash running in an iOS Sim but if it's running thought TestFlight on my iPhone it just crashes.
If I try to delete elements that aren't just created, I don't get this error.
@Query(filter: #Predicate<Note>{ note in
note.isDeleted == false && (note.title != "" || note.content != "")
} ,sort: [SortDescriptor(\Note.isPinned, order: .reverse),SortDescriptor(\Note.createdAt, order: .reverse)]
, animation: .smooth(duration: 0.3)
) private var notes: [Note]
if I delete filter part navigationLink works properly
I've encountered a weird issue with the new Map for iOS 17. In my list, which includes a MapView among other elements, I've observed that with the new initializer, the top and bottom bars are persistently displayed. They don't hide and only appear when scrolling, as they should. This problem doesn't occur with the old, now-deprecated initializer. To illustrate this, I have two screenshots: one with the map enabled and the other with the map disabled, demonstrating the issue.
Here is also my new Map code:
struct MapListRowView: View {
@Binding internal var location: LocationModel
@State internal var user: Bool = true
private var position: CLLocationCoordinate2D { .init(latitude: location.latitude, longitude: location.longitude) }
private var isPad: Bool { UIDevice.current.userInterfaceIdiom == .pad ? true : false }
var body: some View {
Map(bounds: .init(minimumDistance: 1250)) {
if user { UserAnnotation() }
Annotation("", coordinate: position) {
ZStack {
Circle().fill().foregroundColor(.white).padding(1)
Image(systemName: "mappin.circle.fill")
.resizable()
.foregroundColor(.indigo)
}.frame(width: 20, height: 20).opacity(user ? .zero : 1.0)
}
}
.frame(height: isPad ? 200 : 100)
.cornerRadius(8)
.listRowInsets(.init(top: -5, leading: .zero, bottom: -5, trailing: .zero))
.padding(.vertical, 5)
.disabled(true)
}
}
I am developing an iOS app using SwiftUI and have encountered an Auto Layout constraint conflict issue that appears when tapping on a TextField within a LoginView. I've tried several troubleshooting steps but haven't been able to resolve it.
Error Message:
Probably at least one of the constraints in the following list is one you don't want.
Try this:
(1) look at each constraint and try to figure out which you don't expect;
(2) find the code that added the unwanted constraint or constraints and fix it.
(
"<NSLayoutConstraint:0x6000021298b0 'accessoryView.bottom' _UIRemoteKeyboardPlaceholderView:0x10460dd10.bottom == _UIKBCompatInputView:0x1059220e0.top (active)>",
"<NSLayoutConstraint:0x60000217a620 'assistantHeight' SystemInputAssistantView.height == 45 (active, names: SystemInputAssistantView:0x10591ce60 )>",
"<NSLayoutConstraint:0x60000217d090 'assistantView.bottom' SystemInputAssistantView.bottom == _UIKBCompatInputView:0x1059220e0.top (active, names: SystemInputAssistantView:0x10591ce60 )>",
"<NSLayoutConstraint:0x60000217d040 'assistantView.top' V:[_UIRemoteKeyboardPlaceholderView:0x10460dd10]-(0)-[SystemInputAssistantView] (active, names: SystemInputAssistantView:0x10591ce60 )>"
)
Will attempt to recover by breaking constraint
<NSLayoutConstraint:0x60000217d040 'assistantView.top' V:[_UIRemoteKeyboardPlaceholderView:0x10460dd10]-(0)-[SystemInputAssistantView] (active, names: SystemInputAssistantView:0x10591ce60 )>
This error appears in the console when I click on the TextField in my LoginView while running the code on a simulation. The app doesn't crash, but the console indicates there is a constraint conflict related to the keyboard. Here's my LoginView:
struct LoginView: View {
@StateObject var viewModel = LoginViewModel()
var body: some View {
NavigationStack {
VStack {
Spacer()
Image("logo")
.resizable()
.scaledToFit()
.frame(width: 150, height: 100)
VStack {
TextField("Enter your email", text: $viewModel.email)
.autocapitalization(/*@START_MENU_TOKEN@*/.none/*@END_MENU_TOKEN@*/)
.modifier(TextFieldModifier())
SecureField("Enter your password", text: $viewModel.password)
.modifier(TextFieldModifier())
}
Button {
print("Show forgot password")
} label: {
Text("Forgot Password")
.font(.footnote)
.fontWeight(.semibold)
.padding(.top)
.padding(.trailing, 20)
}
.frame(maxWidth: .infinity, alignment: .trailing)
Button {
Task { try await viewModel.signIn() }
} label: {
Text("Login")
.font(.subheadline)
.fontWeight(.semibold)
.foregroundColor(.white)
.frame(width: 360, height: 44)
.background(Color(.black))
.cornerRadius(8)
}
.padding(.vertical)
HStack {
Rectangle()
.frame(width: (UIScreen.main.bounds.width / 2) - 40, height: 0.5)
Text("OR")
.font(.footnote)
.fontWeight(.semibold)
.foregroundColor(.gray)
Rectangle()
.frame(width: (UIScreen.main.bounds.width / 2) - 40, height: 0.5)
}
.foregroundColor(.gray)
HStack {
Image("facebook_logo")
.resizable()
.frame(width: 20, height: 20)
Text("Continue with Facebook")
.font(.footnote)
.fontWeight(.semibold)
.foregroundColor(Color(.systemBlue))
}
.padding(.top, 8)
Spacer()
Divider()
NavigationLink {
AddEmailView()
.navigationBarBackButtonHidden(true)
} label: {
HStack (spacing: 3) {
Text("Don't have an account?")
Text("Sign Up")
.fontWeight(.semibold)
}
.font(.footnote)
}
.padding(.vertical, 16)
}
}
}
}
#Preview {
LoginView()
}
And my TextFieldModifier:
struct TextFieldModifier: ViewModifier {
func body(content: Content) ->some View {
content
.font(.subheadline)
.padding(12)
.background(Color(.systemGray6))
.cornerRadius(10)
.padding(.horizontal, 24)
.padding(.top)
}
}
Attempts to Resolve:
I've checked the TextFieldModifier for any potential issues but it seems standard.
I've tried simplifying the view by removing other elements, but the issue persists.
The issue seems to occur regardless of the simulator device or iOS version I use.
Questions:
What could be causing this Auto Layout constraint conflict in a SwiftUI app?
Are there any known issues with SwiftUI's TextField and keyboard interactions that might lead to such constraints issues?
Any suggestions on how to debug or resolve this constraint conflict?
This is my test code.
import SwiftUI
extension View {
@MainActor func render(scale: CGFloat) -> UIImage? {
let renderer = ImageRenderer(content: self)
renderer.scale = scale
return renderer.uiImage
}
}
struct ContentView: View {
@Environment(\.colorScheme) private var colorScheme
@State private var snapImg: UIImage = UIImage()
var snap: some View {
Text("I'm now is \(colorScheme == .dark ? "DARK" : "LIGHT") Mode!")
.foregroundStyle(colorScheme == .dark ? .red : .green)
}
@ViewBuilder
func snapEx() -> some View {
VStack {
Text("@ViewBuilder I'm now is \(colorScheme == .dark ? "DARK" : "LIGHT") Mode!")
.foregroundStyle(colorScheme == .dark ? .red : .green)
Text("@ViewBuilder I'm now is \(colorScheme == .dark ? "DARK" : "LIGHT") Mode!")
.background(.pink)
Text("@ViewBuilder I'm now is \(colorScheme == .dark ? "DARK" : "LIGHT") Mode!")
.background(.purple)
Text("@ViewBuilder I'm now is \(colorScheme == .dark ? "DARK" : "LIGHT") Mode!")
.foregroundStyle(colorScheme == .dark ? .red : .green)
Text("@ViewBuilder I'm now is \(colorScheme == .dark ? "DARK" : "LIGHT") Mode!")
.foregroundStyle(colorScheme == .dark ? .red : .green)
}
}
@ViewBuilder
func snapView() -> some View {
VStack {
Text("Text")
Text("Test2")
.background(.green)
snap
snapEx()
}
}
var body: some View {
let snapView = snapView()
VStack {
snapView
Image(uiImage: snapImg)
Button("Snap") {
snapImg = snapView.render(scale: UIScreen.main.scale) ?? UIImage()
}
}
}
}
When using ImageRenderer, there are some problems with converting View to images.
For example, Text cannot automatically modify the foreground color of Dark Mode.
This is just a simple test code, not just Text.
How should I solve it?
Description:
I have developed an app that allows users to create folders, and I'm utilizing the DisclosureGroup component for this functionality. While I am currently using Firebase, for the purpose of this demonstration, I have simplified the setup using a @State variable.
The issue I am encountering revolves around an unusual animation behavior during the entrance and deletion of the DisclosureGroup. It's worth noting that this behavior is specific to the DisclosureGroup component. I have experimented with other components, such as a VStack with text or a custom DisclosureGroup, and encountered no problems.
This problem emerged specifically with the release of iOS 17; there were no issues with iOS 16.
I would appreciate any insights or suggestions on resolving this animation behavior with the DisclosureGroup on iOS 17.
Thank you.
Video demonstration of the problem:
https://youtube.com/shorts/pkz3LMXhlsg
Code implementation
State Variable:
@State var testFolders: [Folder] = [
Folder(id: "1", nameFolder: "test1", noteFolder: "", timestamp: Date().timeIntervalSince1970),
Folder(id: "2", nameFolder: "test2", noteFolder: "", timestamp: Date().timeIntervalSince1970 + 20000),]
Button to append a new folder:
.toolbar{
ToolbarItem{
Button{
testFolders.append(Folder(id: "3", nameFolder: "test3", noteFolder: "", timestamp: Date().timeIntervalSince1970 + 500000))
} label: {
Image(systemName: "folder.badge.plus")
}
}
}
Displaying in a List:
List {
Section {
listFolders
}
}
.listStyle(.plain)
.animation(.default, value: viewModel.folders)
.animation(.default, value: viewModel.plans)
private var listFolders: some View {
ForEach(testFolders.sorted(by: { $0.timestamp > $1.timestamp }), id: \.id) { folder in
DisclosureGroup(isExpanded: Binding<Bool>(
get: { viewModel.expanded.contains(folder.id) },
set: { isExpanding in
if isExpanding {
viewModel.expanded.insert(folder.id)
} else {
viewModel.expanded.remove(folder.id)
}
}
)) {
} label: {
Text(folder.nameFolder)
.font(.headline)
.swipeActions {
Button {
viewModel.getFolderPlans(plans: viewModel.plans, folder: folder)
viewModel.folderToShowInfo = folder
viewModel.isShowingDetail = true
} label: {
Label("Edit", systemImage: "square.and.pencil")
}
.tint(Color.indigo)
Button {
withAnimation{
_ = viewModel.expanded.remove(folder.id)
}
viewModel.folderToDelete = folder
viewModel.showDialog = true
} label: {
Label("Delete", systemImage: "trash.fill")
}
.tint(Color.red)
}
}
}