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
691
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
579
Jan ’25
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
390
Jan ’25
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
243
Jan ’25
SwiftUI and UIImage memory leak
I’m experiencing significant performance and memory management issues in my SwiftUI application when displaying a large number of images using LazyVStack within a ScrollView. The application uses Swift Data to manage and display images. Here’s the model I’m working with: @Model final class Item { var id: UUID = UUID() var timestamp: Date = Date.now var photo: Data = Data() init(photo: Data = Data(), timestamp: Date = Date.now) { self.photo = photo self.timestamp = timestamp } } extension Item: Identifiable {} The photo property is used to store images. However, when querying Item objects using Swift Data in a SwiftUI ScrollView, the app crashes if there are more than 100 images in the database. Scrolling down through the LazyVStack loads all images into memory leading to the app crashing when memory usage exceeds the device’s limits. Here’s my view: A LazyVStack inside a ScrollView displays the images. struct LazyScrollView: View { @Environment(\.modelContext) private var modelContext @State private var isShowingPhotosPicker: Bool = false @State private var selectedItems: [PhotosPickerItem] = [] @Query private var items: [Item] var body: some View { NavigationStack { ScrollView { LazyVStack { ForEach(items) { item in NavigationLink { Image(uiImage: UIImage(data: item.photo)!) .resizable() .scaledToFit() } label: { Image(uiImage: UIImage(data: item.photo)!) .resizable() .scaledToFit() } } } } .navigationTitle("LazyScrollView") .photosPicker(isPresented: $isShowingPhotosPicker, selection: $selectedItems, maxSelectionCount: 100, matching: .images) .onChange(of: selectedItems) { Task { for item in selectedItems { if let data = try await item.loadTransferable(type: Data.self) { let newItem = Item(photo: data) modelContext.insert(newItem) } } try? modelContext.save() selectedItems = [] } } } } } Based on this: How can I prevent SwiftUI from loading all the binary data (photo) into memory when the whole view is scrolled until the last item? Why does SwiftUI not free memory from the images that are not being displayed? Any insights or suggestions would be greatly appreciated. Thank you! I will put the full view code in the comments so anyone can test if needed.
2
0
702
Jan ’25
Rectangle change size by swipe
Hi,, How can I make a rectangle become taller as I swipe down on my trackpad?" struct BlueRectangleView: View { var body: some View { VStack { Rectangle() .fill(Color.blue) .frame(width: 200, height: 100) .cornerRadius(10) .shadow(radius: 5) .padding() } .frame(maxWidth: .infinity, maxHeight: .infinity) .background(Color.white) } } struct BlueRectangleView_Previews: PreviewProvider { static var previews: some View { BlueRectangleView() } }
2
0
284
Jan ’25
INUIHostedViewControlling ViewController's Life Cycle Events not being Called
I am implementing a new Intents UI Extension and am noticing that the viewWillDisappear, viewDidDisappear, and deinit methods are not being called on my UIViewController that implements INUIHostedViewControlling, when pressing the "Done" button and dismissing the UIViewController. This causes the memory for the UI Extension to slowly increase each time I re-run the UI Extension until it reaches the 120MB limit and crashes. Any ideas as to what's going on here and how to solve this issue? Worth noting that while the memory does continuously increase on iOS versions before iOS 17, only in 17 and later does the 120MB memory limit kick in and crash the extension.
2
0
518
Feb ’25
Reduce padding, spacing between list section header and search bar
Anyone know how to reduce the padding between list section header (plain style) and search bar? I have tried all available method on google but none work. The default list style does not have this big padding/space between the section header and the search bar. struct Demo: View { @State private var searchText: String = "" var body: some View { NavigationStack { List { Section { ForEach(0..<100) { index in Text("Sample value for \(index)") } } header: { Text("Header") .font(.headline) } } .listStyle(.plain) .navigationTitle("Demo") .navigationBarTitleDisplayMode(.inline) .searchable(text: $searchText) } } }
0
0
239
Feb ’25
SwiftUIKit Got double back button and blank screen
I tried to update my ios from 17.2 to 18.1 on my iphone 14 pro. I use this device for testing my apps. when i go to my sdk, i got double back button and when i clicked the back button it will go to blank screen here is the ss double back button got blank screen its never happened on ios 17 and below i use coordinator and UINavigationController anyone have solutions?
1
0
296
Jan ’25
Why timer isn't working with button in SwiftUI
.onReceive construction isn't working with button long press gesture but tap is working, it increases count by 1. Construction should increase count every 0.5 seconds if button pressed struct Test: View { @State private var count = 0 @State private var isLongPressed = false var body: some View { VStack { Text("Count: \(count)") Button("Increase") { count += 1 print("Button tapped") } .onLongPressGesture { isLongPressed = true print("Long press started") } .onLongPressGesture(minimumDuration: 0) { isLongPressed = false print("Long press ended") } } .onReceive(Timer.publish(every: 0.5, on: .main, in: .common).autoconnect()) { _ in if isLongPressed { count += 1 print("Count increased: \(count)") } } } }
1
0
389
Jan ’25
SwiftUI PKCanvasView bounds
I am creating a Bible app with SwiftUI using Text in the background and a PKCanvasView in the front to mark the text and take notes. The user can modify the font and its size and you can navigate to different books and chapters. Each chapter's text has a different size causing the PKCanvasView to have varying sizes. The width of the canvas is always the same but the height changes based on these parameters I just mentioned. If the chapter is long and the height of the canvas exceeds 4000 or some settings cause the text to make the views bound to go beyond 4000, the drawing will enlarge or appear to be occurring in a different location than my pencil. As soon as I lift my pencil, the drawing snaps to the place it belongs. var body: some View { HStack(spacing: 0) { // Main content container ScrollView { ZStack { // Text content VStack { if let chapter = viewModel.currentChapterText { HStack { Text(AttributedString(chapter.html(fontName: fontName, fontSize: fontSize, showVerses: showVerse, showFootnotes: showFootnotes))) .padding() .frame(width: textWidth, alignment: .leading) Color.clear } .frame(width: canvasWidth) } else { Text("Select a book to begin reading") .foregroundColor(.gray) } } // Drawing canvas overlay if showingDrawingTools { DrawingCanvasView( canvasView: $canvasView, toolPicker: toolPicker, frame: CGSize(width: deviceWidth, height: deviceHeight), onSave: saveDrawing ) } } } } .onChange(of: viewModel.currentChapter) { oldValue, newValue in print("BibleContentView - chapter text changed") } }
Topic: UI Frameworks SubTopic: SwiftUI
2
0
272
Jan ’25
QLPreviewingController can access previewed file, but cannot load files referenced by the previewed file
I have an app on the Mac App Store (so sandboxed) that includes a QuickLook Preview Extension that targets Markdown files. It established a QLPreviewingController instance for the macOS QuickLook system to access and it works. I'm in the process of updating it so that it displays inline images referenced in the file as well as styling the file's text. However, despite setting Downloads folder read-only access permission (and user-selected, though I know that shouldn't be required: no open/save dialogs here) in the extension's entitlements, Sandbox refuses too allow access to the test image: I always get a deny(1) file-read-data error in the log. FWIW, the test file is referenced in the source Markdown as an absolute unix file path. I've tried different signings and no joy. I’ve tried placing the referenced image in various other locations. Also no joy. All I can display is the error-case bundle image for 'missing image'. Question is, is this simply something that QuickLook extensions cannot do from within the sandbox, or am I missing something? Is there anything extra I can do to debug this?
0
0
413
Jan ’25
SwiftData integration for coexistence with CoreData Error: Persistent truncated
When integrating SwiftData for an already existing app that uses CoreData as data management, I encounter errors. When building the ModelContainer for the first time, the following error appears: Error: Persistent History (184) has to be truncated due to the following entities being removed (all Entities except for the 2 where I defined a SwiftData Model) class SwiftDataManager: ObservableObject { static let shared = SwiftDataManager() private let persistenceManager = PersistenceManager.shared private init(){} lazy var modelContainer: ModelContainer = { do { let storeUrl = persistenceManager.storeURL() let schema = Schema([ HistoryIncident.self, HistoryEvent.self ]) let modelConfig = ModelConfiguration(url: storeUrl) return try ModelContainer(for: schema, configurations: [modelConfig]) } catch { fatalError("Could not create ModelContainer: \(error)") } }() } @Model public class HistoryIncident { var missionNr: String? @Relationship(deleteRule: .cascade) var events: [HistoryEvent]? public init(){} } @Model class HistoryEvent { var decs: String? var timestamp: Date? init(){} } As soon as I call the following function. func addMockEventsToCurrentHistorie() { var descriptor = FetchDescriptor<HistoryIncident>() let key = self.hKey ?? "" descriptor.predicate = #Predicate { mE in key == mE.key } let historyIncident = try? SwiftDataManager.shared.modelContext.fetch(descriptor).first guard var events = historyIncident?.events else {return} events.append(contentsOf: createEvents()) } I get the error: CoreData: error: (1) I/O error for database at /var/mobile/Containers/Data/Application/55E9D59D-48C4-4D86-8D9F-8F9CA019042D/Library/ Private Documents/appDatabase.sqlite. SQLite error code:1, 'no such column: t0.Z1EVENTS' /var/mobile/Containers/Data/Application/55E9D59D-48C4-4D86-8D9F-8F9CA019042D/Library/ Private Documents/appDatabase.sqlite. SQLite error code:1, 'no such column: t0.Z1EVENTS' with userInfo of { NSFilePath = "/var/mobile/Containers/Data/Application/55E9D59D-48C4-4D86-8D9F-8F9CA019042D/Library/ Private Documents/appDatabase.sqlite"; NSSQLiteErrorDomain = 1; }
1
0
645
Feb ’25
Excessive ressource usage with NavigationLinks in LazyVStack
When a large number of NavigationLinks is within a LazyVStack (or LazyVGrid), ressource usage gets higher (and stays high) the further a user scrolls down. A simple example to reproduce this: NavigationStack { ScrollView { LazyVStack { ForEach(0..<5000) { number in NavigationLink(value: number) { Text("Number \(number)") } } } } .navigationDestination(for: Int.self) { number in Text("Details for number \(number)") } } List does not exhibit this behavior but is not suitable for my use case.
1
0
255
Jan ’25
Observe currentEDRHeadroom for changes
Is there a way to observe the currentEDRHeadroom property of UIScreen for changes? KVO is not working for this property... I understand that I can query the current headroom in the draw(...) method to adapt the rendering. However, our apps only render on-demand when the user changes parameters. But we would also like to re-render when the current EDR headroom changes to adapt the tone mapping to the new environment. The only solution we've found so far is to continuously query the screen for changes, which doesn't seem ideal. It would be better if the property would be observable via KVO or if there would be a system notification to listen for. Thanks!
2
0
1.3k
Feb ’25
Confusion about units for new WeatherKit visibility items
I am really confused by some of the new data returned in WeatherKit for iOS 18. The visibility (of an object) was already being returned in HourWeather as a Measurement. iOS 18 added max/min visibility (of terrain) in DayWeather. BUT instead of a Measurement it's just a Double. HourWeather: /// The distance at which an object can be clearly seen. /// /// The amount of light and weather conditions like fog, mist, and smog affect visibility. public var visibility: Measurement<UnitLength> DayWeather's comment: /// The maximum distance at which terrain is visible for the day. /// /// The amount of light, and weather conditions like fog, mist, and smog affect visibility. @available(iOS 18.0, macOS 15.0, tvOS 18.0, watchOS 11.0, visionOS 2.0, *) public var maximumVisibility: Double This makes it sound like the new items are also a distance and not a percentage. Why wasn't Measurement used so the unit would be clear? Documentation doesn't explain this either. I'm hoping that this isn't being returned in the unit used by the current locale because my app lets you specify what unit to use for temperature, length, etc regardless of locale. Since all the temperature, length, etc data returned had used Measurement that was possible. The iOS weather app refers to the lowest/highest visibility in my preferred unit, which is miles.
1
0
413
Jan ’25
Window color Changed After Exiting Immersive Mode
Create an Empty visionOS App like this. starts in windowed mode, when I enter immersive mode and then exit back to windowed mode, I notice that the window appears dimmer. I start a simple project with settings as image shown below, and took screenShots of my window before and after entering immersive space then quit, compare them, the color value did become dimmer. The issue is reliably repeatable in a given room. If this issue is experienced, adjusting the display brightness to the maximum value and then back to the initial setting will restore the colors to the correct state. Force to exit the app then reopen it can do the same restoration.https://drive.google.com/file/d/1m-a4ghNlSkHhAQuvOCF_IAfcdYeJA14j/view?usp=sharing
1
0
274
Feb ’25
SwiftUI Issues on iOS 16: App Freezes, Buttons Unresponsive, and Missing Data (Works Fine on iOS 17)
Hi everyone, I’m experiencing significant issues with my SwiftUI app when running on iOS 16. These issues are not present in iOS 17, where everything works as expected. I’m hoping someone can provide insights or suggestions on how to address these problems. The Problems App Freezing: In certain views, the app becomes completely unresponsive when running on iOS 16. There are no clear patterns or console logs pointing to the source of the freeze. Unresponsive Buttons: Buttons stop working in some views. Tapping them does nothing, even though the logic and bindings are correct. Missing Data: Data fetched from services (remote APIs) or local storage doesn’t show up in the UI. Expected Behavior The app should handle user interactions and display data correctly on both iOS 16 and iOS 17, without freezes or unresponsive elements. Environment: Xcode Version: Xcode 15.4 Deployment Target: iOS 16 Testing Devices: iPhone 14 with iOS 17.6.1, iPhone 13 with iOS 18.1.1, iPhone 8 with iOS 16.4, iPhone 12 with 16.4, iPhone 8 Plus with iOS 16.0, iPhone 8 Plus with 16.7.10
Topic: UI Frameworks SubTopic: SwiftUI
3
0
353
Jan ’25