Explore the various UI frameworks available for building app interfaces. Discuss the use cases for different frameworks, share best practices, and get help with specific framework-related questions.

All subtopics
Posts under UI Frameworks topic

Post

Replies

Boosts

Views

Activity

A Summary of the WWDC25 Group Lab - UI Frameworks
At WWDC25 we launched a new type of Lab event for the developer community - Group Labs. A Group Lab is a panel Q&A designed for a large audience of developers. Group Labs are a unique opportunity for the community to submit questions directly to a panel of Apple engineers and designers. Here are the highlights from the WWDC25 Group Lab for UI Frameworks. How would you recommend developers start adopting the new design? Start by focusing on the foundational structural elements of your application, working from the "top down" or "bottom up" based on your application's hierarchy. These structural changes, like edge-to-edge content and updated navigation and controls, often require corresponding code modifications. As a first step, recompile your application with the new SDK to see what updates are automatically applied, especially if you've been using standard controls. Then, carefully analyze where the new design elements can be applied to your UI, paying particular attention to custom controls or UI that could benefit from a refresh. Address the large structural items first then focus on smaller details is recommended. Will we need to migrate our UI code to Swift and SwiftUI to adopt the new design? No, you will not need to migrate your UI code to Swift and SwiftUI to adopt the new design. The UI frameworks fully support the new design, allowing you to migrate your app with as little effort as possible, especially if you've been using standard controls. The goal is to make it easy to adopt the new design, regardless of your current UI framework, to achieve a cohesive look across the operating system. What was the reason for choosing Liquid Glass over frosted glass, as used in visionOS? The choice of Liquid Glass was driven by the desire to bring content to life. The see-through nature of Liquid Glass enhances this effect. The appearance of Liquid Glass adapts based on its size; larger glass elements look more frosted, which aligns with the design of visionOS, where everything feels larger and benefits from the frosted look. What are best practices for apps that use customized navigation bars? The new design emphasizes behavior and transitions as much as static appearance. Consider whether you truly need a custom navigation bar, or if the system-provided controls can meet your needs. Explore new APIs for subtitles and custom views in navigation bars, designed to support common use cases. If you still require a custom solution, ensure you're respecting safe areas using APIs like SwiftUI's safeAreaInset. When working with Liquid Glass, group related buttons in shared containers to maintain design consistency. Finally, mark glass containers as interactive. For branding, instead of coloring the navigation bar directly, consider incorporating branding colors into the content area behind the Liquid Glass controls. This creates a dynamic effect where the color is visible through the glass and moves with the content as the user scrolls. I want to know why new UI Framework APIs aren’t backward compatible, specifically in SwiftUI? It leads to code with lots of if-else statements. Existing APIs have been updated to work with the new design where possible, ensuring that apps using those APIs will adopt the new design and function on both older and newer operating systems. However, new APIs often depend on deep integration across the framework and graphics stack, making backward compatibility impractical. When using these new APIs, it's important to consider how they fit within the context of the latest OS. The use of if-else statements allows you to maintain compatibility with older systems while taking full advantage of the new APIs and design features on newer systems. If you are using new APIs, it likely means you are implementing something very specific to the new design language. Using conditional code allows you to intentionally create different code paths for the new design versus older operating systems. Prefer to use if #available where appropriate to intentionally adopt new design elements. Are there any Liquid Glass materials in iOS or macOS that are only available as part of dedicated components? Or are all those materials available through new UIKit and AppKit views? Yes, some variations of the Liquid Glass material are exclusively available through dedicated components like sliders, segmented controls, and tab bars. However, the "regular" and "clear" glass materials should satisfy most application requirements. If you encounter situations where these options are insufficient, please file feedback. If I were to create an app today, how should I design it to make it future proof using Liquid Glass? The best approach to future-proof your app is to utilize standard system controls and design your UI to align with the standard system look and feel. Using the framework-provided declarative API generally leads to easier adoption of future design changes, as you're expressing intent rather than specifying pixel-perfect visuals. Pay close attention to the design sessions offered this year, which cover the design motivation behind the Liquid Glass material and best practices for its use. Is it possible to implement your own sidebar on macOS without NSSplitViewController, but still provide the Liquid Glass appearance? While technically possible to create a custom sidebar that approximates the Liquid Glass appearance without using NSSplitViewController, it is not recommended. The system implementation of the sidebar involves significant unseen complexity, including interlayering with scroll edge effects and fullscreen behaviors. NSSplitViewController provides the necessary level of abstraction for the framework to handle these details correctly. Regarding the SceneDelagate and scene based life-cycle, I would like to confirm that AppDelegate is not going away. Also if the above is a correct understanding, is there any advice as to what should, and should not, be moved to the SceneDelegate? UIApplicationDelegate is not going away and still serves a purpose for application-level interactions with the system and managing scenes at a higher level. Move code related to your app's scene or UI into the UISceneDelegate. Remember that adopting scenes doesn't necessarily mean supporting multiple scenes; an app can be scene-based but still support only one scene. Refer to the tech note Migrating to the UIKit scene-based life cycle and the Make your UIKit app more flexible WWDC25 session for more information.
Topic: UI Frameworks SubTopic: General
0
0
651
Jun ’25
SwiftUI charts, how do I align these X axis labels correctly?
Hi there, so I have this chart that's taking in a Date for it's x values and a time interval for their y values. For some reason, the labels aren't centering on each bar, the only fix I see is to add an offset to each label but that seems hacky. My code: Chart { ForEach(weekBreakdownArr, id: \.startDate) { bd in BarMark( x: .value("Date", bd.startDate), y: .value("Duration", bd.durationWorkDone), width: .fixed(15) ) .foregroundStyle(Color.redYarn) .cornerRadius(2) } //... } // shownXValues are just the start dates in an array .chartXAxis { AxisMarks(position: .automatic, values: shownXValues) { val in AxisValueLabel { Text("Th") .useAppFont(size: 12, relativeTo: .body, weight: .regular) } } }
1
0
652
Dec ’24
On a navigation bar created by a DocumentGroup, items disappear after renaming the file from the automatic Rename button in the Title Menu
On an iPad or iPhone running iPadOS / iOS 18.2 (built with Xcode 16.2), run the WritingApp sample code from https://developer.apple.com/documentation/SwiftUI/Building-a-document-based-app-with-SwiftUI from WWDC24 Then add the following struct to the project: struct NavigationBarToolbar: ToolbarContent { var body: some ToolbarContent { ToolbarItem(placement: .secondaryAction) { Button("Button 1", systemImage: "1.circle") { } } ToolbarItem(placement: .secondaryAction) { Button("Button 2", systemImage: "2.circle") { } } ToolbarItem(placement: .secondaryAction) { Button("Button 3", systemImage: "3.circle") { } } ToolbarItem(placement: .secondaryAction) { Button("Button 4", systemImage: "4.circle") { } } ToolbarItem(placement: .secondaryAction) { Button("Button 5", systemImage: "5.circle") { } } } } Comment out the original toolbar in the sample project and replace with: .toolbar(content: NavigationBarToolbar.init) Run the project and open or create a document Click on the TitleMenu and choose Rename, in order to rename the file Type in a new name and press Enter. Notice how the items of the toolbar disappear —— This issue has been submitted as feedback with number FB16100225 This issue is linked to the following feedbacks: FB14855728 FB14855668 FB14849205 FB12343963 FB15164292
0
1
290
Dec ’24
SwiftUI Audio File Export via draggable
Hey everyone, TL;DR How do I enable a draggable TableView to drop Audio Files into Apple Music / Rekordbox / Finder? Intro / skip me I've been dabbling into Swift / SwiftUI for a few weeks now, after roughly a decade of web development. So far I've been able to piece together many things, but this time I'm stuck for hours with no success using Forums / ChatGPT / Perplexity / Trial and Error. The struggle Sometimes the target doesn't accept the dropping at all sometimes the file data is failed to be read when the drop succeeds, then only as a stream in apple music My lack of understanding / where exactly I'm stuck I think the right way is to use UTType.fileUrl but this is not accepted by other applications. I don't understand low-level aspects well enough to do things right. The code I'm just going to dump everything here, it includes failed / commented out attempts and might give you an Idea of what I'm trying to achieve. // // Tracks.swift // Tuna Family // // Created by Jan Wirth on 12/12/24. // import SwiftySandboxFileAccess import Files import SwiftUI import TunaApi struct LegacyTracks: View { @State var tracks: TunaApi.LoadTracksQuery.Data? func fetchData() { print("fetching data") Network.shared.apollo.fetch(query: TunaApi.LoadTracksQuery()) { result in switch result { case .success(let graphQLResult): self.tracks = graphQLResult.data case .failure(let error): print("Failure! Error: \(error)") } } } @State private var selection = Set<String>() var body: some View { Text("Tracks").onAppear{ fetchData() } if let tracks = tracks?.track { Table(of: LoadTracksQuery.Data.Track.self, selection: $selection) { TableColumn("Title", value: \.title) } rows : { ForEach(tracks) { track in TableRow(track) .draggable(track) // .draggable((try? File(path: track.dropped_source?.path ?? "").url) ?? test_audio.url) // This causes a compile-time error // .draggable(test_audio.url) // .draggable(DraggableTrack(url: test_audio.url)) // .itemProvider { // let provider = NSItemProvider() // if let path = self.dropped_source?.path { // if let f = try? File(path: path) { // print("Transferring", f.url) // // // } // } // // provider.register(track) // return provider // } // This does not } } .contextMenu(forSelectionType: String.self) { items in // ... Button("yoooo") {} } primaryAction: { items in print(items) // This is executed when the row is double clicked } } else { Text("Loading") } // } } } //extension Files.File: Transferable { // public static var transferRepresentation: some TransferRepresentation { // FileRepresentation(exportedContentType: .audio) { url in // SentTransferredFile( self.) // } // } //} struct DraggableTrack: Transferable { var url: URL public static var transferRepresentation: some TransferRepresentation { FileRepresentation (exportedContentType: .fileURL) { item in SentTransferredFile(test_audio.url, allowAccessingOriginalFile: true) } // FileRepresentation(contentType: .init(filenameExtension: "m4a")) { // print("file", $0) // print("Transferring fallback", test_audio.url) // return SentTransferredFile(test_audio.url, allowAccessingOriginalFile: true) // } // importing: { received in // // let copy = try Self.(source: received.file) // return Self.init(url: received.file) // } // ProxyRepresentation(exporting: \.url.absoluteString) } } extension LoadTracksQuery.Data.Track: @retroactive Identifiable { } import UniformTypeIdentifiers extension LoadTracksQuery.Data.Track: @retroactive Transferable { // static func getKind() -> UTType { // var kind: UTType = UTType.item // if let path = self.dropped_source?.path { // if let f = try? File(path: path) { // print("Transferring", f.url) // if (f.extension == "m4a") { // kind = UTType.mpeg4Audio // } // if (f.extension == "mp3") { // kind = UTType.mp3 // } // if (f.extension == "flac") { // kind = UTType.flac // } // if (f.extension == "wav") { // kind = UTType.wav // } // // } // } // return kind // } public static var transferRepresentation: some TransferRepresentation { ProxyRepresentation { $0.dropped_source?.path ?? "" } FileRepresentation(exportedContentType: .fileURL) { <#Transferable#> in SentTransferredFile(<#T##file: URL##URL#>, allowAccessingOriginalFile: <#T##Bool#>) } // FileRepresentation(contentType: .fileURL) { // print("file", $0) // if let path = $0.dropped_source?.path { // if let f = try? File(path: path) { // print("Transferring", f.url) // return SentTransferredFile(f.url, allowAccessingOriginalFile: true) // } // } // print("Transferring fallback", test_audio.url) // return SentTransferredFile(test_audio.url, allowAccessingOriginalFile: true) // } // importing: { received in // // let copy = try Self.(source: received.file) // return Self.init(_fieldData: received.file) // } // ProxyRepresentation(exporting: \.title) } }
0
0
442
Dec ’24
I Need Help!
I am trying to carry out repairs on my computer, it is an old MacBook Pro which I really appreciate, and it works very well, before attempting a hardware repair, I am exhausting all the software resources, in one of its support forums I found a supposed solution, I just can't see the assigned plist, but I see that it appears in the example as root within xcode, could you help me with what the steps would be to enter root mode and thus be able to make the relevant adjustment , I attach the link to the example. thank you so much https://discussions.apple.com/thread/3114550?sortBy=rank) The example can be found in Grant Bennet-Alder coment
Topic: UI Frameworks SubTopic: AppKit
1
0
353
Dec ’24
Why can't I use Task in an iOS only package?
Getting this error: 'Task' is only available in macOS 10.15 or newerSourceKit LoggerForPreviews.swift(130, 9): Add 'if #available' version check LoggerForPreviews.swift(129, 24): Add @available attribute to enclosing static method LoggerForPreviews.swift(5, 20): Add @available attribute to enclosing actor Does it have something to do with developing in VSCode? import Foundation import SwiftUI // Logger: A concise, globally accessible logging utility for SwiftUI previews public final actor PreviewLogger: Sendable { // LogLevel: Defines severity levels for logging public enum LogLevel: Int, Sendable, CaseIterable { // Define cases based on LOG_LEVEL_MAP case trace, debug, verbose, info, notice, warning, error, critical, fatal // Computed property to get order based on case declaration private var order: Int { switch self { case .trace: return 0 case .debug: return 1 case .verbose: return 2 case .info: return 3 case .notice: return 4 case .warning: return 5 case .error: return 6 case .critical: return 7 case .fatal: return 8 } } public var description: String { // Use capitalized raw value for description return String(describing: self).uppercased() } // Static function to compare log levels static func >= (lhs: LogLevel, rhs: LogLevel) -> Bool { return lhs.order >= rhs.order } } // Shared instance for global access public static let shared = PreviewLogger() // Current log level public var logLevelThreshold: LogLevel = .info private init() {} // Configure the logger's log level public func configure(logLevelThreshold: LogLevel) { self.logLevelThreshold = logLevelThreshold } // Helper function to center text within a given width private func centered(_ text: String, in separator: String) -> String { let totalLength = separator.count let textLength = text.count if textLength >= totalLength { return text } let padding = (totalLength - textLength) / 2 let padString = String(repeating: " ", count: padding) return padString + text } // Main logging function public func log( _ message: String, level: LogLevel = .info, file: String = #file, function: String = #function, line: Int = #line, callerFile: String? = nil, callerFunction: String? = nil, callerLine: Int? = nil ) { #if DEBUG guard ProcessInfo.processInfo.environment["XCODE_RUNNING_FOR_PREVIEWS"] == "1" else { return } guard level >= logLevelThreshold else { return } let fileName = (file as NSString).lastPathComponent let cleanFunction = function.replacingOccurrences(of: "(_:file:function:line:)", with: "") let levelIcon: String switch level { case .trace: levelIcon = "🔍" case .debug: levelIcon = "🛠️" case .verbose: levelIcon = "📝" case .info: levelIcon = "ℹ️" case .notice: levelIcon = "📢" case .warning: levelIcon = "⚠️" case .error: levelIcon = "❌" case .critical: levelIcon = "🚨" case .fatal: levelIcon = "💀" } let header = "[\(levelIcon) \(level.description)]" let separator = "· · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · ·" let finalSeparator = "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" let centeredHeader = centered(header, in: separator) var output = """ \n\(separator) \(centeredHeader) """ let locationInfo = "📍 \(fileName):\(line) ➜ \(cleanFunction)" let centeredLocation = centered(locationInfo, in: separator) output += "\n\(centeredLocation)" if let callerFile = callerFile, let callerLine = callerLine { let callerFileName = (callerFile as NSString).lastPathComponent let callerInfo = "📱 Called from: \(callerFileName):\(callerLine)" let centeredCallerInfo = centered(callerInfo, in: separator) output += "\n\(centeredCallerInfo)" } output += """ \n\(separator)\n\(message)\n\(finalSeparator) """ print(output) #endif } // Static Methods public static func configure(logLevelThreshold: LogLevel) { Task { await shared.configure(logLevelThreshold: logLevelThreshold) } } public static func log( _ message: String, level: LogLevel = .info, file: String = #file, function: String = #function, line: Int = #line, callerFile: String? = nil, callerFunction: String? = nil, callerLine: Int? = nil ) { Task { await shared.log( message, level: level, file: file, function: function, line: line, callerFile: callerFile, callerFunction: callerFunction, callerLine: callerLine ) } } }
1
0
255
Dec ’24
How to connect a @Parameter of a Tip to my app's state?
I have an observable object which is a model a view. I also have a Tip (from TipKit) with @Parameter and a rule. The source of truth for the state is in the observable object, however the Tip needs to be updated when state changes. So how do I bind between the two? The way I was thinking was to sink updates from objectWillChange and check if Tips parameter needs to be updated or add didSet if it a @Published property. But I am not sure this is the best practice. Schematic example: class MyModel: ObservableObject { struct TapSubmitTip: Tip { @Parameter static var isSubmitButtonEnabled: Bool = false var title: Text { Text("Tap \"Submit\" to confirm your selection.") } var rules: [Rule] { #Rule(Self.$isSubmitButtonEnabled) { $0 == true } } } let tapSubmitTip = TapSubmitTip() var objectWillChangeCancallable: AnyCancellable! // Used by the view to enable or disable the button var isSubmitButtonEnabled: Bool { // Some logic to determine if button should be enabled. } init() { objectWillChangeCancallable = objectWillChange.sink { [weak self] void in guard let self else { return } if isSubmitButtonEnabled { TapSubmitTip.isSubmitButtonEnabled = true } } } ... // Call objectWillChange or update published properties as needed. ... }
0
0
412
Dec ’24
Button Responsiveness Problems in SwiftUI Apps After Upgrading to iOS 18
I've been encountering significant issues with button responsiveness across my entire SwiftUI application after upgrading to iOS 18. While everything worked as expected on iOS 17, buttons across various views now sometimes fail to respond to initial taps and require a long press to trigger actions. Here is a sample of a button within a toolbar, similar issues are occurring with other buttons throughout the app: .toolbar { ToolbarItem(placement: .topBarLeading) { Button(action: { DispatchQueue.main.async { navigationCoordinator.pushScreen(.account) } }) { Image("User") .resizable() .scaledToFit() .frame(width: 24.5, height: 24.5) } } } Expected Behavior: All buttons in the application should respond to a simple tap without requiring additional user effort, maintaining consistency with their behavior on iOS 17. Actual Behavior: On iOS 18, the responsiveness of buttons throughout the application is inconsistent; sometimes they react to a simple tap, and other times they only respond to a long press. This erratic behavior disrupts the user experience and hinders basic app functionality. I am looking to understand whether this is a widespread issue with the new OS version and if there are any fixes or patches anticipated from Apple. Thank you for your assistance!
Topic: UI Frameworks SubTopic: SwiftUI
8
7
3.2k
Dec ’24
Multi layer delegate table missing
我最近在18.0,18.1,18.1.1上监测到一个特殊的崩溃,无法复现,且页面日志都跟键盘有关,有没有什么思路能够处理这个问题。 0 CoreFoundation 0x00000001a224d08c __exceptionPreprocess + [ : 164] 1 libobjc.A.dylib 0x000000019f54f2e4 objc_exception_throw + [ : 88] 2 Foundation 0x00000001a161e15c _userInfoForFileAndLine 3 UIKitCore 0x00000001a56c6b2c -[UIView _multiLayerDelegatesTableCreateIfNecessary:] + [ : 208] 4 UIKitCore 0x00000001a56c6b7c -[UIView _registerMultiLayerDelegate:] + [ : 36] 5 UIKitCore 0x00000001a4ceadb8 -[_UIPortalView setSourceView:] + [ : 132] 6 UIKitCore 0x00000001a5a35888 -[_UIPortalView initWithSourceView:] + [ : 68] 7 UIKitCore 0x00000001a5a5e038 -[_UITextMagnifiedLoupeView initWithSourceView:] + [ : 444] 8 UIKitCore 0x00000001a5f0f894 +[UITextLoupeSession _makeLoupeViewForSourceView:selectionWidget:orientation:] + [ : 84] 9 UIKitCore 0x00000001a5f0fa34 +[UITextLoupeSession _beginLoupeSessionAtPoint:fromSelectionWidgetView:inView:orientation:] + [ : 304] 10 UIKitCore 0x00000001a55a0b9c -[UITextRefinementTouchBehavior textLoupeInteraction:gestureChangedWithState:location:translation:velocity:modifierFlags:shouldCancel:] + [ : 1756] 11 UIKit 0x000000025aff6310 -[UITextRefinementTouchBehaviorAccessibility textLoupeInteraction:gestureChangedWithState:location:translation:velocity:modifierFlags:shouldCancel:] + [ : 216]
Topic: UI Frameworks SubTopic: UIKit
0
0
320
Dec ’24
@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?
Topic: UI Frameworks SubTopic: SwiftUI
5
0
333
Dec ’24
Keep ScrollView position when adding items on the top using onAppear / onScrollTargeVisibilityChange
Related Post: Keep ScrollView position when adding items on the top I was trying to implement a message view using ScrollView + LazyVStack. This view requires pagination so I used onScrollTargeVisibilityChange modifier to detect if the first item appears on screen and a new page needs to be loaded. I learnt from the above post that scrollPositon modifier can help keep the scroll position. I tested the method mentioned in that post -- use a button to add new items to the top -- and it worked. However, when use onScrollTargeVisibilityChange modifier to add items, the view automatically scrolls to the top and cause the following loop: first item in the list appears on screen --> load and insert more items to the top --> scroll view scrolls to top --> first item appears --> load more data --> scroll to top --> first item ... --> more data... --> top ... Until it generates the error ScrollTargetVisibilityChange tried to update multiple times per frame. Here is the simplified code. struct Item: Identifiable { var id: UUID = .init() var content: String } struct ScrollViewTest: View { @State private var items: [Item] = (0...30).map {Item(content:"\($0)")}.reversed() @State private var itemID: Item.ID? @State private var page: Int = 0 var body: some View { ScrollView { LazyVStack { ForEach(items) {item in Text(item.content) .frame(height: 30) } } .scrollTargetLayout() } .scrollPosition(id: $itemID) .defaultScrollAnchor(.bottom) .onScrollTargetVisibilityChange(idType: Item.ID.self) { onScreenItemIDs in if onScreenItemIDs.first == items.first?.id { page += 1 let newItems = (page*30+1 ... (page+1)*30).map {Item(content:"\($0)")} items.insert(contentsOf: newItems.reversed(), at: 0) } } .toolbar { Button("Add") { page += 1 let newItems = (page*30+1 ... (page+1)*30).map {Item(content:"\($0)")} items.insert(contentsOf: newItems.reversed(), at: 0) } } } } I want to load data while scrolling without the need of pressing any buttons. How can I solve this problem?
0
1
289
Dec ’24
Adding logging to a SwiftUI View's body var
Pretty sure this is a no-no, but asking just in case there's an easy way to make this work struct DocumentContentView: View { private static let logger = Logger( subsystem: "mySubsystem", category: String(describing: Self.self) ) var body: some View { VStack { Text("Hello") logger.trace("hello") } } } This code generates the following compile error at the logger.trace line buildExpression is unavailable: this expression does not conform to View I suspect every line of the body var (or any @ViewBuilder - designated code?) needs to 'return' a View. Is this correct? or more importantly any work arounds other than putting some/all of the view contents in a. func()?
2
1
2.6k
Dec ’24
swift ui in tableview cell gesture sometimes not call back
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let message = self.parent.viewModel.messages[indexPath.row] // var cell: RCBaseMessageCell? = tableView.dequeueReusableCell(withIdentifier: String( message.type.rawValue)) as? RCBaseMessageCell var cell = tableView.dequeueReusableCell(withIdentifier: "cell") if #available(iOS 16.0, *) { cell?.contentConfiguration = UIHostingConfiguration { Text("123").onTapGesture { print("123") } } return cell } on ios 18.1 onTapGesture sometimes will not callback ,but ios 17 16 is ok,how can i fix it
1
0
256
Dec ’24
Identifying UIKit Api's failure
I have a UIKit application and it contains multiple UI components like UIWindow, UIView, UIButton, etc. I wanted to perform error handling for different OS calls in my application. For example, when creating a UIImage using init(named:) initialiser, the documentation clearly states that if the UIImage object cannot be created then the initialiser returns nil value. However, there are other UI components like UIButton (or like UIView), which when created using init(frame:) initialiser, the documentation does not mention for any return value. I wanted to know how to identify If the UIButton initialisation has failed? How is it that apple recommends should we handle these api's, If they fail to create a button. suppose If there is a case where it fails due to insufficient memory. Or is it that apple guarantees the Api's never fail?Is there some exception that is throw? I wanted somewhat detailed answer to these questions.
Topic: UI Frameworks SubTopic: UIKit Tags:
2
0
353
Dec ’24
siri caused the app to crash
Some users experience this kind of crash: NSInternalInconsistencyException:Use of the class INVocabulary requires the entitlement com.apple.developer.siri. Make sure you have enabled the Siri capability in your Xcode project. During app startup, calling the following code causes a crash: INVocabulary *vocabulary = [INVocabulary sharedVocabulary]; But our project definitely has siri configured to be available. Now that we can't figure it out, is it a bug in the system?
Topic: UI Frameworks SubTopic: UIKit Tags:
1
0
378
Dec ’24
UIKit Internal bug: Unbalanced call to _endOcclusion, please file a feedback report with any information you have that helps reproduce this bug!
Hi, I'm getting a bug in SwiftUI when dismissing a sheet and then hitting the back button or swiping to go back in a navigation stack. This issue happens inconsistently but causes undesirable behavior where the screen freezes in a partially dismissed state but does not crash. A user can click on another tab and return back and the view will have completed dismissal. The error seems more likely to happen if the time between dismissing the sheet and navigating backwards is minimal. I've experimenting using different forms of navigation, NavigationStack using NavigationPaths and NavigationDestinations, NavigationLinks, NavigationViews, etc. The issue persists. Is there a nice fix or intended fix to this issue coming soon? Thank you!
Topic: UI Frameworks SubTopic: UIKit
1
0
336
Dec ’24
Discovered a bug where Alert button colors are changed by the tint modifier.
I used .tint(.yellow) to change the default back button color. However, I noticed that the color of the alert button text, except for .destructive, also changed. Is this a bug or Apple’s intended behavior? this occurs in iOS 18.1 and 18.1.1 Below is my code: // App struct TintTestApp: App { var body: some Scene { WindowGroup { MainView() .tint(.yellow) } } } // MainView var mainContent: some View { Text("Next") .foregroundStyle(.white) .onTapGesture { isShowingAlert = true } .alert("Go Next View", isPresented: $isShowingAlert) { Button("ok", role: .destructive) { isNextButtonTapped = true } Button("cancel", role: .cancel) { } } } thank you!
Topic: UI Frameworks SubTopic: SwiftUI Tags:
1
1
505
Dec ’24
Macos 15.2 beta 4 App Crash
I have a SwiftUI based program that has compiled and run consistently on previous macos versions. After upgrading to 15.2 beta 4 to address a known issue with TabView in 15.1.1, my app is now entering a severe hang and crashing with: "The window has been marked as needing another Update Contraints in Window pass, but it has already had more Update Constraints in Window passes than there are views in the window. .<SwiftUI.AppKitWindow: 0x11d82a800> 0x87 (2071) {{44,0},{1468,883}} en" Is there a known bug that could be causing this crash or known change in the underlying layout model?
Topic: UI Frameworks SubTopic: SwiftUI
1
0
404
Dec ’24