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
Implement two lists side by side with SwiftUI on iPad
I'm currently building an App using a TabView as the main navigation method. In my app I would like to build a page similar to the Top Charts in the native App Store App with two lists side by side: So far I came up with this code (simplified demo): import SwiftUI struct Demo: View { var body: some View { TabView { Tab("Main Tab", systemImage: "tray.and.arrow.down.fill") { NavigationStack { HStack { List { Text("Left List") } List { Text("Right List") } } .navigationTitle("Demo") .navigationBarTitleDisplayMode(.inline) } } } } } #Preview { Demo() } However, I’m encountering a couple of issues: • Scrolling to the top of the left list doesn’t trigger the toolbar background effect, and the content overlaps with the tabs in a strange way. Scrolling to the top of the right list works as expected. • The navigation title is always hidden. I haven’t been able to find a solution to these problems. What would be the correct approach? Thank you!
1
0
568
Jan ’25
Initialize view struct with @StateObject parameter
May I inquire about the differences between the two ways of view under the hood in SwiftUI? class MyViewModel: ObservableObject { @Published var state: Any init(state: Any) { self.state = state } } struct MyView: View { @StateObject var viewModel: MyViewModel var body: some View { // ... } } struct CustomView: View { let navigationPath: NavigationPath @StateObject var viewModel: MyViewModel var body: some View { Button("Go to My View") { navigationPath.append(makeMyView()) } } } // Option 1: A viewModel is initialized outside view's initialization func makeMyView(state: Any) -> some View { let viewModel = MyViewModel(state: state) MyView(viewModel: viewModel) } // Option 2: A viewModel is initialized inside view's initialization func makeMyView(state: Any) -> some View { MyView(viewModel: MyViewModel(state: state)) } For option 1, the view model will be initialized whenever custom view is re-rendered by changes whereas the view model is only initialized once when the view is re-rendered for option 2. So what happens here?
0
0
228
Dec ’24
MacCatalyst Scene Frame needs adjustment
I don't know why, but for my MacCatalyst target, I have to make my view controller Y orgin 36 and the subtract the view height by 36 points, or the view is clipped. The following works in my main UIViewController, but feels super hacky. I'd feel better if I understood the issue and addressed it properly. override func viewWillLayoutSubviews() { super.viewWillLayoutSubviews() #if targetEnvironment(macCatalyst) if view.frame.origin.y < 1 { let f = UIApplication.shared.sceneBounds let newFrame = CGRect(x: 0.0, y: 36, width: f.size.width, height: f.size.height - 36) self.view.frame = newFrame } #endif } My guess is it starts the view under the title bar, but I have these set in the view controller: self.extendedLayoutIncludesOpaqueBars = false self.edgesForExtendedLayout = []
1
0
438
Jan ’25
SwiftUI crashed on iOS16 when use List with .animation
When I use the following code List { ForEach(data.items, id: \.knowledgeInfo.mediaID) { item in SelectableKnowledgeListItem(knowledgeData: item, baseID: data.knowledgeBaseID, isSelectionMode: $isSelectionMode, selectedItems: $selectedItems) .KnowledgeListItemStyle() } // 添加底部加载更多 if !data.isEnd && !isRefreshing { ProgressView() .frame(maxWidth: .infinity, alignment: .center) .onAppear { self.isRefreshing = true manager.getKnowledgeList(knowledgeBaseID: data.knowledgeBaseID, completion: { self.isRefreshing = false }) } } } .animation(.interactiveSpring) .scrollContentBackground(.hidden) .environment(\.defaultMinListHeaderHeight, 7) The number of Views rendered in the List remains unchanged after he adds an item to data.items (data is an ObservedObject, items is Published) at runtime.When I removed .animation(.interactiveSpring), it would be processed normally.And if I perform a delete operation after adding, it will cause a crash. *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Invalid update: invalid number of sections. The number of sections contained in the collection view after the update (11) must be equal to the number of sections contained in the collection view before the update (10), plus or minus the number of sections inserted or deleted (1 inserted, 1 deleted).
Topic: UI Frameworks SubTopic: SwiftUI
0
0
189
Dec ’24
SwiftUI infinite rendering loop when using a custom Binding to a dictionary-based store
I’m building a SwiftUI app where the struct AppGroup is identified by a UUID and stored in a dictionary. My Task model has appGroupId: UUID?. In TaskDetailView, I create a custom Binding<AppGroup> from the store, then navigate to AppGroupDetailView. However, when I tap the NavigationLink, the console spams logs, CPU hits 100%, and it never stabilizes. Relevant Code AppGroupStore (simplified) class AppGroupStore: ObservableObject { @Published var appGroupsDict: [UUID: AppGroup] = [:] func updateAppGroup(_ id: UUID, appGroup: AppGroup) { appGroupsDict[id] = appGroup } // Returns a binding so views can directly read/write the AppGroup by id func getBinding(withId id: UUID?) -> Binding<AppGroup> { Binding( get: { if let id = id { return self.appGroupsDict[id] ?? .empty } return .empty }, set: { newValue in print("New value set for \(newValue.name)") self.updateAppGroup(newValue.id, appGroup: newValue) } ) } // ... } AppGroup is a simple struct: struct AppGroup: Identifiable, Codable { let id: UUID var name: String var apps: [String] static let empty = AppGroup(id: UUID(), name: "Empty", apps: []) } TaskDetailView (main part) struct TaskDetailView: View { @Binding var task: ToDoTask // has task.appGroupId: UUID? @EnvironmentObject var appGroupStore: AppGroupStore var body: some View { let appGroup = appGroupStore.getBinding(withId: task.appGroupId) print("Task load") // prints infinitely, CPU 100% return List { // ... NavigationLink(destination: AppGroupDetailView(appGroup: appGroup)) { Text(appGroup.wrappedValue.name) } } .navigationTitle(task.name) } } AppGroupDetailView (simplified) struct AppGroupDetailView: View { @Binding var appGroup: AppGroup // ... var body: some View { List { ForEach(appGroup.apps, id: \.self) { app in Text(app) } } .navigationTitle(appGroup.name) } } Symptoms: Tapping the NavigationLink leads to infinite “Task load” logs and 100% CPU usage. The set closure (“New value set for...”) is never called, so it’s not repeatedly writing. If I replace the Binding<AppGroup> with a read-only approach (just accessing the dictionary), it does not get stuck. Question: What might cause SwiftUI to keep re-rendering the body indefinitely, even if my custom get closure doesn’t explicitly mutate the state? Are there known pitfalls when using a dictionary-based store and returning a Binding like this? Any help is much appreciated! Thanks in advance for your insights!
0
0
238
Jan ’25
@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
icloud password reset UI does not show buttons.
As can be seen in the screenshot attached, I can not see the options in this window. A prompt window before this also did not show any buttons in the visible space. However, I made a guess and could get to this window by clicking on what I think was "Ok" or something similar. But on this I could not do any action and had to force quit the app.
Topic: UI Frameworks SubTopic: General Tags:
0
0
265
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
Application threw exception NSInternalInconsistencyException: Multi layer delegate table missing.
I recently detected a special crash on 18.0, 18.1, 18.1.1, 18.2,18.3 which cannot be repeated, and the page logs are related to the keyboard, is there any idea to deal with this problem? Exception Category: nsexception Exception Type: EXC_CRASH (SIGABRT) Exception Codes: 0x00000000 at 0x0000000000000000 Crashed Thread: 0 CrashDoctor Diagnosis: Application threw exception NSInternalInconsistencyException: Multi layer delegate table missing. Thread 0 Crashed: 0 CoreFoundation 0x00000001869d87cc __exceptionPreprocess + [ : 164] 1 libobjc.A.dylib 0x0000000183cab2e4 objc_exception_throw + [ : 88] 2 Foundation 0x0000000185da88d8 _userInfoForFileAndLine 3 UIKitCore 0x0000000189e78074 -[UIView _multiLayerDelegatesTableCreateIfNecessary:] + [ : 208] 4 UIKitCore 0x0000000189e780c4 -[UIView _registerMultiLayerDelegate:] + [ : 36] 5 UIKitCore 0x00000001894874c0 -[_UIPortalView setSourceView:] + [ : 132] 6 UIKitCore 0x000000018a1eb6bc -[_UIPortalView initWithSourceView:] + [ : 68] 7 UIKitCore 0x000000018a213ea4 -[_UITextMagnifiedLoupeView initWithSourceView:] + [ : 444] 8 UIKitCore 0x000000018a6c461c +[UITextLoupeSession _makeLoupeViewForSourceView:selectionWidget:orientation:] + [ : 84] 9 UIKitCore 0x000000018a6c47bc +[UITextLoupeSession _beginLoupeSessionAtPoint:fromSelectionWidgetView:inView:orientation:] + [ : 304] 10 UIKitCore 0x0000000189d50ce0 -[UITextRefinementTouchBehavior textLoupeInteraction:gestureChangedWithState:location:translation:velocity:modifierFlags:shouldCancel:] + [ : 1756] 11 UIKit 0x0000000240e309e0 -[UITextRefinementTouchBehaviorAccessibility textLoupeInteraction:gestureChangedWithState:location:translation:velocity:modifierFlags:shouldCancel:] + [ : 216] 12 UIKitCore 0x000000018a4d45b4 -[UITextRefinementInteraction loupeGestureWithState:location:translation:velocity:modifierFlags:shouldCancel:] + [ : 124] 13 UIKitCore 0x000000018a4d3f74 -[UITextRefinementInteraction loupeGesture:] + [ : 548] 14 UIKitCore 0x000000018952eac4 -[UIGestureRecognizerTarget _sendActionWithGestureRecognizer:] + [ : 128] 15 UIKitCore 0x000000018952e934 _UIGestureRecognizerSendTargetActions + [ : 92] 16 UIKitCore 0x000000018952e6f4 _UIGestureRecognizerSendActions + [ : 284] 17 UIKitCore 0x00000001891e1b28 -[UIGestureRecognizer _updateGestureForActiveEvents] + [ : 572] 18 UIKitCore 0x00000001891b3724 _UIGestureEnvironmentUpdate + [ : 2488] 19 CoreFoundation 0x000000018697a1f4 __CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__ + [ : 36] 20 CoreFoundation 0x0000000186979f98 __CFRunLoopDoObservers + [ : 552] 21 CoreFoundation 0x00000001869a9028 __CFRunLoopRun + [ : 948] 22 CoreFoundation 0x00000001869a8830 CFRunLoopRunSpecific + [ : 588] 23 GraphicsServices 0x00000001d29881c4 GSEventRunModal + [ : 164] 24 UIKitCore 0x000000018950eeb0 -[UIApplication _run] + [ : 816] 25 UIKitCore 0x00000001895bd5b4 UIApplicationMain + [ : 340] 26 顺丰小哥 0x0000000104423cc0 main + [main.m : 13] 27 (null) 0x00000001ac396ec8 0x0 + 7184412360
Topic: UI Frameworks SubTopic: UIKit
0
0
284
Dec ’24
Carplay在CPNowPlayingTemplate显示图片的败,且不可点击
System: iOS 18.1.1 When connected to Carplay, after playing a song, check the playback page CPNowPlayingTemplate. This error appears on the BMW car, as shown in the picture: In our project, this is achieved using the following methods: UIImage *image1 = [UIImage imageNamed:@"imageName"];; CPNowPlayingImageButton *button1 = [[CPNowPlayingImageButton alloc] initWithImage:image1 handler:^(__kindof CPNowPlayingButton * _Nonnull action) { //do something }]; UIImage *image2 = [UIImage imageNamed:@"imageName"];; CPNowPlayingImageButton *button2 = [[CPNowPlayingImageButton alloc] initWithImage:image2 handler:^(__kindof CPNowPlayingButton * _Nonnull action) { //do something }]; NSArray<CPNowPlayingButton *> *buttons; buttons = @[button1,button2]; [[CPNowPlayingTemplate sharedTemplate] updateNowPlayingButtons:buttons]; Is there any way to solve this problem?
Topic: UI Frameworks SubTopic: UIKit Tags:
1
0
382
Jan ’25
Adopt UIFindInteraction across multiple views
We are currently trying to adopt the newly introduced find bar in our app. The app: The app is a text editor with a main text view. However it includes nested views (for text like footnotes) that are presented as modal sheets. So you tap on the footnote within the main text, a form sheet is presented with the contents of the footnote ready to be edited. We have an existing search implementation, but are eager to move to the system-provided UI. Connecting the find bar through a custom UIFindSession with our existing implementation is working without any issues. The Problem: Searching for text does not only work in the main text view, but also nested text (like footnotes). Let's say I have a text containing the word "iPhone" both in the main text and the footnote. In our existing implementation, stepping from the search match to the next one would open the modal and highlight the match in the nested text. The keyboard would stay open. With the new UIFindInteraction this is not working however. As soon as a modal form sheet is presented, the find interaction closes. By looking at the stack trace I can see a private class called UIInputWindowController that cleans up input accessory views after the modal gets presented. I believe it is causing the find panel to give up its first responder state. I noticed that opening popovers appears to be working fine. Is there a way to alter the presentation of the nested text so that the view is either not modal or able to preserve the current find session? Or is this unsupported behavior and we should try and look for a different way? The thing that really confuses me is that this appears to work without issue in Notes.app. There the find bar is implemented as well. There are multiple views that can be presented while the find bar is open. Move Note is one of them. The view appears as a modal sheet. It keeps the find bar open and active, though its tint color matches the deactivated one of the main Notes view. The find bar is still functional with the text field being active and the overlay updating in the background. This behavior appears to be a bug in the Notes app, but is exactly what we want for our use case. I attached some images: Two are from the Notes app, two from a test project demonstrating the problem. Opening a modal view closes the find bar there.
2
0
1.3k
Jan ’25
Dynamically Update Complex UI Views in SwiftUI
I am working on a SwiftUI project where I need to dynamically update the UI by adding or removing components based on some event. The challenge is handling complex UI structures efficiently while ensuring smooth animations and state management. Example Scenario: I have a screen displaying a list of items. When a user taps an item, additional details (like a subview or expanded section) should appear dynamically. If the user taps again, the additional content should disappear. The UI should animate these changes smoothly without causing unnecessary re-renders. My Current Approach: I have tried using @State and if conditions to toggle views, like this: struct ContentView: View { @State private var showDetails = false var body: some View { VStack { Button("Toggle Details") { showDetails.toggle() } if showDetails { Text("Additional Information") .transition(.slide) // Using animation } } .animation(.easeInOut, value: showDetails) } } However, in complex UI scenarios where multiple components need to be shown/hidden dynamically, this approach is not maintainable and could cause performance issues. I need help with the below questions. Questions: State Management: Should I use @State, @Binding, or @ObservedObject for handling dynamic UI updates efficiently? Best Practices: What are the best practices for structuring SwiftUI views to handle dynamic updates without excessive re-renders? Performance Optimization: How can I prevent unnecessary recomputations when updating only specific UI sections? Animations & Transitions: What is the best way to apply animations smoothly while toggling visibility of multiple components? Advanced Approaches: Are there better techniques using @EnvironmentObject, ViewBuilder, or even GeometryReader for dynamically adjusting UI layouts? Any insights, code examples, or resources would be greatly appreciated.
0
0
341
Jan ’25
XCode breakpoint possible for "Publishing changes from within view updates is not allowed, this will cause undefined behavior."?
Dear Sirs, I'm searching for the most straightforward way to identify the root of a "Publishing changes from within view updates is not allowed, this will cause undefined behavior." warning. It is a complex SwiftUI project and I think there should be a better way than just try and error with disabling/removing and enabling/adding different screen elements to check if the warning still is shown. I tried to set a symbolic breakpoint for "os_log" in my XCode project and indeed this is triggered right before the warning appears but the callstack doesn't give me a direct hint to the part of my code which causes this warning. What would be the most direct way and is there something like an exception handler in such cases? Thanks and best regards, Johannes
0
0
471
Jan ’25
UITabBarController y psoition issue for iOS 18
I am trying to give bottom padding to tabbar i.e ** tabBarFrame.origin.y = view.frame.height - tabBarHeight - 30** but it is not moving up from bottom, it gets sticked to bottom = 0 and the tabbar content moving up taher than tabbar itself.. Code snippet is - `i override func viewDidLayoutSubviews() { super.viewDidLayoutSubviews() let tabBarHeight: CGFloat = 70 // Custom height for the capsule tab bar var tabBarFrame = tabBar.frame tabBarFrame.size.height = tabBarHeight tabBarFrame.size.width = view.frame.width - 40 tabBarFrame.origin.y = view.frame.height - tabBarHeight - 30 tabBarFrame.origin.x = 20 tabBar.frame = tabBarFrame tabBar.layer.cornerRadius = tabBarHeight / 2 tabBar.clipsToBounds = true view.bringSubviewToFront(tabBar) }` Can anyone please help to resolve the issue for iOS 18, it is coming in iOS 18 rest previous versions are fine with the code.
0
0
326
Jan ’25
Unexpected Insertion of U+2004 (Space) When Using UITextView with Pinyin Input on iOS 18
I encountered an issue with UITextView on iOS 18 where, when typing Pinyin, extra Unicode characters such as U+2004 are inserted unexpectedly. This occurs when using a Chinese input method. Steps to Reproduce: 1. Set up a UITextView with a standard delegate implementation. 2. Use a Pinyin input method to type the character “ㄨ”. 3. Observe that after the character “ㄨ” is typed, extra spaces (U+2004) are inserted automatically between the characters. Code Example: class ViewController: UIViewController { @IBOutlet weak var textView: UITextView! override func viewDidLoad() { super.viewDidLoad() // Do any additional setup after loading the view. } } extension ViewController: UITextViewDelegate { func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool { print("shouldChangeTextIn: range \(range)") print("shouldChangeTextIn: replacementText \(text)") return true } func textViewDidChange(_ textView: UITextView) { let currentText = textView.text ?? "" let unicodeValues = currentText.unicodeScalars.map { String(format: "U+%04X", $0.value) }.joined(separator: " ") print("textViewDidChange: textView.text: \(currentText)") print("textViewDidChange: Unicode Scalars: \(unicodeValues)") } } Output: shouldChangeTextIn: range {0, 0} shouldChangeTextIn: replacementText ㄨ textViewDidChange: textView.text: ㄨ textViewDidChange: Unicode Scalars: U+3128 ------------------------ shouldChangeTextIn: range {1, 0} shouldChangeTextIn: replacementText ㄨ textViewDidChange: textView.text: ㄨ ㄨ textViewDidChange: Unicode Scalars: U+3128 U+2004 U+3128 ------------------------ shouldChangeTextIn: range {3, 0} shouldChangeTextIn: replacementText ㄨ textViewDidChange: textView.text: ㄨ ㄨ ㄨ textViewDidChange: Unicode Scalars: U+3128 U+2004 U+3128 U+2004 U+3128 This issue may affect text processing, especially in cases where precise text manipulation is required, such as calculating ranges in shouldChangeTextIn.
5
0
1k
Jan ’25
Is MapKit.mapCameraKeyframeAnimator broken on macOS 15.2?
Hi! I'm attempting to run the Quakes Sample App^1 from macOS. I am running breakpoints and confirming the mapCameraKeyframeAnimator is being called: .mapCameraKeyframeAnimator(trigger: selectedId) { initialCamera in let start = initialCamera.centerCoordinate let end = quakes[selectedId]?.location.coordinate ?? start let travelDistance = start.distance(to: end) let duration = max(min(travelDistance / 30, 5), 1) let finalAltitude = travelDistance > 20 ? 3_000_000 : min(initialCamera.distance, 3_000_000) let middleAltitude = finalAltitude * max(min(travelDistance / 5, 1.5), 1) KeyframeTrack(\MapCamera.centerCoordinate) { CubicKeyframe(end, duration: duration) } KeyframeTrack(\MapCamera.distance) { CubicKeyframe(middleAltitude, duration: duration / 2) CubicKeyframe(finalAltitude, duration: duration / 2) } } But I don't actually see any map animations taking place when that selection changes. Running the application from iPhone simulator does show the animations. I am building from Xcode Version 16.2 and macOS 15.2. Are there known issues with this API on macOS?
0
0
288
Dec ’24