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

UICollectionView unwanted content offset change on invalidating layout
I have issue with unwanted changing offset in collection view to top or to near top. It is happening in collection view with vertical scroll when estimatedItemSize is not set to zero (main factor). If estimatedItemSize is zero it is always fine. It is SDK that provides items that should be loaded in few cells, items have dynamic height which is received from server and can be updated several times. Scenario when it happens (when was noticed) is 2 sections, in section 0 item is at index 4 of 14, section 1 is with only one cell with dynamic height item. If specific item is at index 0 in section 0 or have 1 cell per section (tried 15 sections and set items in sections 5 and 15) all is good regardless of estimatedItemSize. When new height is received if I call invalidateLayout or reloadItemAtIndexPaths it will “jump”. That same height is set in sizeForItemAtIndexPath. In some combinations it happens and in some not and that is the most annoying part. I tried setting estimated height to received height and it didn’t help (other cell may be smaller or larger). Also if I put items in one section at indexes 4 and 14 it “jumps”. I managed to make it work by setting at specific moment estimatedItemSize to zero then put back to one that SDK user set and didn’t see any issues but I was wondering if there is any other solution for this and did anyone had issue like this. It would be nice to have solution to keep one estimatedItemSize if it is not the default one (zero).
Topic: UI Frameworks SubTopic: UIKit
0
0
248
Sep ’24
TabView with ScrollView: scroll position ID not updating when tapping Tab item
When working with SwiftUI TabView and ScrollView at root level with scrollPosition(id:anchor:), after tapping on Tab item the ScrollView scrolls to the top, but the scroll position ID does not get updated. struct ContentView: View { @State var positionID: Int? var body: some View { TabView { Tab("Test", systemImage: "house") { ScrollView(.vertical) { LazyVStack(pinnedViews: [.sectionHeaders]) { ForEach(0 ... 100, id: \.self) { index in Text("\(index)") } } .scrollTargetLayout() } .scrollPosition(id: $positionID, anchor: .top) .onChange(of: positionID) { _, newValue in print(newValue) } } } } } FB15964820
0
0
517
Dec ’24
SwiftUI warning for "Publishing changes from within view updates" on macOS
I have a simple example of a List with multiple selection. When I run it on macOS, and select an item from the list, it works fine but I get a warning in the console: Publishing changes from within view updates is not allowed, this will cause undefined behavior Interestingly, it doesn't produce a purple 'issue' in the Issues navigator, but as I change selection, I keep getting this warning. Also, the warning doesn't show when running the same code on iOS. Here is code to reproduce it: struct TestListSelection: View { let testArray = [TestItem(itemValue: 1), TestItem(itemValue: 2), TestItem(itemValue: 3), TestItem(itemValue: 4)] @ObservedObject var listOptions: TestListViewModel var body: some View { List (selection: $listOptions.multipleSelection) { Section("Header") { ForEach (testArray, id: \.self) { item in Button { print("row tapped - \(item.itemValue)") } label: { VStack { HStack { Text(item.itemString) } } } .buttonStyle(.plain) } } } .listStyle(.plain) } } public struct TestItem: Identifiable, Hashable { public let id = UUID() let itemValue: Int var itemString: String { get { return "test \(itemValue)" } } } @MainActor public class TestListViewModel: NSObject, ObservableObject { @Published public var multipleSelection = Set<TestItem>() } I annotated the view model with @MainActor as suggested in other threads, but it doesn't silence the warning. If I move the multipleSelection into the view itself, and make it a @State variable (bypassing the viewModel completely), it works and doesn't produce a warning. But I need it work so I can pass in selection from the UIKit part of the app as well. I also can't migrate to @Observable because my main project has to support iOS15 and above. Any clue why this is happening on macOS specifically, and what I can do to avoid it?
0
0
522
Oct ’24
SwiftUI: Picker text color not changing until reloading view
My picker looks like this: Picker("Color", selection: $backgroundColor.animation(), content: { ForEach(TransactionCategory.Colors.allCases, id: \.self) { color in Text(color.rawValue) .tag(color) .foregroundStyle(color.getColor()) } }) This changes a tint color which is applied to the entire tabview. I can see that it's working because the buttons in the top tab bar are changing color as I change the picker value. However, the color of the text inside the picker is not changing until I go back one view and then come back to this view. I tried setting an ID on the picker and then updating it when the picker value changes, but that didn't work. Any ideas?
0
2
496
Dec ’24
ScrollView vs List horizontal padding based on iPhone screen size
In my app, most views use List for all tabs. However, due to a custom design, I switched one tab to use ScrollView. I quickly noticed that, unlike List, which applies default padding around the entire view and its items, ScrollView has no such built-in padding. Initially, I assumed that applying a simple .padding(.horizontal) would give the items in ScrollView the same padding as List, but that wasn’t the case. It turns out List adjusts its padding based on screen size. For larger iPhones, like the Plus and Pro Max models, List uses 20px padding, whereas regular-sized iPhones (including the Pro) use 16px. This discrepancy creates an inconsistency when trying to replicate the same padding behavior with ScrollView. Thus, my question how can I apply this conditional padding and/or if there's an API to get the value of the default padding used by List? Also, there’s a difference in padding depending on whether you run the app in the simulator or on a physical device, even if both the simulator and the physical device are the same model and iOS version. iPhone 13 iOS 17.4 Simulator: iPhone 13 iOS 17.4 Physical device: As you can see simulator for iPhone 13 has what I assume 20px paddings for List and List items. So the default padding applied to items in ScrollView is misaligned. iPhone 15 Pro Max iOS 18.0 Physical device and Simulator: In summary, it seems that simulators consistently apply 20px padding for List, while physical devices adjust between 20px and 16px based on screen size. Meanwhile, .padding(.horizontal) always applies 16px and doesn’t dynamically switch to 20px on larger screens. Any thoughts how to work around this? Code example: struct ContentView: View { var body: some View { VStack(spacing: 0) { ScrollView { ForEach(0..<50) { i in Text("Item #\(i)") .padding(.horizontal) .frame(maxWidth: .infinity, alignment: .leading) .background(.orange) .padding(.horizontal) } } List { ForEach(0..<50) { i in Text("Item #\(i)") .background(.green) } } } } }
0
2
521
Oct ’24
UIDocumentPickerViewController: open to specific folder
Hi, With UIDocumentPickerViewController, there is a directoryURL property that says we can use to 'specify the starting directory for the document picker'. But it's not clear how to get the directory of a folder in iCloud Drive / Files app. How can I get the 'root' directory for a user's iCloud Drive or Dropbox folder, or the Downloads folder on their device, that I could pass to this directoryURL to make it easier for the user to pick their files? Thanks.
0
0
470
Dec ’24
AppLaunchTimeoutError
Hi. I tried to launch SwiftUI preview. But I got an error "AppLaunchTimeoutError" I attach the diagnostics. Does anyone know how to fix this problem? memo.txt
Topic: UI Frameworks SubTopic: SwiftUI
0
1
357
Oct ’24
UIDocumentPickerViewController directoryURL no longer opening correct folder
Since iOS 18, I have gotten user reports that the UIDocumentPickerViewController directoryURL is no longer opening the correct folder. Instead it is just loading the root directory of the Files app/iCloud files. Did something change in iOS 18 that I need to account for? Not all users are having this issue, but some are and they are frustrated because a major feature of my app was to allow users to save files at the ubiquityURL. I use the following to get the path: NSURL *rootDirectory = [[[NSFileManager defaultManager] URLForUbiquityContainerIdentifier:nil] URLByAppendingPathComponent:[NSString stringWithFormat:@"Documents/Photos/%@", folderName]]; Is there something that I need to do differently now in iOS 18 to prevent this from happening?
0
1
457
Dec ’24
Canvas view crashing with Core Graphics-based drawing
One of my SwiftUI applications using a Canvas view started to crash with Xcode 16. It was working flawlessly with Xcode 15. I was able to come up with a minimal SwiftUI app that shows the issue: @main struct CanvasTest: App { var body: some Scene { WindowGroup { VStack { Canvas { context, size in context.withCGContext { cgContext in let z = Int(size.width / 3.0) for i in 0..<18000 { // crashes from 17413 on cgContext.beginPath() cgContext.move(to: CGPoint(x: (i % z) * 3, y: (i / z) * 2)) cgContext.addLine(to: CGPoint(x: (i % z) * 3 + 2, y: (i / z) * 2)) cgContext.strokePath() } } } } } } } The canvas displays 18000 lines and the context.withCGContext invocation also completes successfully. Yet, the application crashes immediately after like this (details below): Exception Type: EXC_BREAKPOINT (SIGTRAP) Exception Codes: 0x0000000000000001, 0x00000001800eabb4 Termination Reason: SIGNAL 5 Trace/BPT trap: 5 Terminating Process: exc handler [2162] I was wondering if anyone else noticed that change and found a way to fix it? Alternatively, I am looking for workarounds. I have to be able to display large drawings created via core context-based graphics. Is this worth reporting to Apple? Thanks already now for any help and advice. Hardware Model: Mac15,9 Process: CanvasTest [2162] Path: /Users/USER/Library/Developer/CoreSimulator/Devices/0C372C7C-3D00-48AA-8124-799CB9A35C1E/data/Containers/Bundle/Application/EBAEC7A2-C93D-48B7-9754-4F3F54A33084/CanvasTest.app/CanvasTest Identifier: com.objecthub.CanvasTest Version: 1.0 (1) Code Type: ARM-64 (Native) Role: Foreground Parent Process: launchd_sim [98324] Coalition: com.apple.CoreSimulator.SimDevice.0C372C7C-3D00-48AA-8124-799CB9A35C1E [58431] Responsible Process: SimulatorTrampoline [3499] Date/Time: 2024-12-01 14:33:07.7617 +0100 Launch Time: 2024-12-01 14:33:07.4151 +0100 OS Version: macOS 15.1.1 (24B91) Release Type: User Report Version: 104 Exception Type: EXC_BREAKPOINT (SIGTRAP) Exception Codes: 0x0000000000000001, 0x00000001800eabb4 Termination Reason: SIGNAL 5 Trace/BPT trap: 5 Terminating Process: exc handler [2162] Triggered by Thread: 0 Application Specific Information: Abort Cause 268435470 Thread 0 Crashed:: Dispatch queue: com.Metal.CommandQueueDispatch 0 libxpc.dylib 0x1800eabb4 _xpc_connection_release_message.cold.1 + 60 1 libxpc.dylib 0x1800c9910 _xpc_connection_release_message + 240 2 libxpc.dylib 0x1800c80b4 _xpc_connection_enqueue + 264 3 libxpc.dylib 0x1800c8b9c xpc_connection_send_message + 128 4 MTLSimDriver 0x2275c6e7c -[MTLSimCommandQueue submitCommandBuffers:count:] + 368 5 Metal 0x19eabdfd4 -[_MTLCommandQueue _submitAvailableCommandBuffers] + 480 6 Metal 0x19eabe4ac __40-[_MTLCommandQueue submitCommandBuffer:]_block_invoke + 24 7 libdispatch.dylib 0x180178de0 _dispatch_client_callout + 16 8 libdispatch.dylib 0x180188ac8 _dispatch_lane_barrier_sync_invoke_and_complete + 92 9 Metal 0x19eabe46c -[_MTLCommandQueue submitCommandBuffer:] + 112 10 MTLSimDriver 0x2275c5fc8 -[MTLSimCommandBuffer commitAndWaitUntilSubmitted] + 40 11 RenderBox 0x1c6e9015c RB::RenderFrame::~RenderFrame() + 240 12 RenderBox 0x1c6e6e9dc __38-[RBLayer displayWithBounds:callback:]_block_invoke.27 + 500 13 libdispatch.dylib 0x180178de0 _dispatch_client_callout + 16 14 libdispatch.dylib 0x180188ac8 _dispatch_lane_barrier_sync_invoke_and_complete + 92 15 RenderBox 0x1c6e6de38 -[RBLayer displayWithBounds:callback:] + 2480 16 RenderBox 0x1c6e6d46c -[RBLayer display] + 172 17 QuartzCore 0x18b0c7e74 CA::Layer::layout_and_display_if_needed(CA::Transaction*) + 392 18 QuartzCore 0x18affca50 CA::Context::commit_transaction(CA::Transaction*, double, double*) + 464 19 QuartzCore 0x18b02b260 CA::Transaction::commit() + 652 20 UIKitCore 0x185af0f70 __34-[UIApplication _firstCommitBlock]_block_invoke_2 + 32 21 CoreFoundation 0x18041b58c __CFRUNLOOP_IS_CALLING_OUT_TO_A_BLOCK__ + 20 22 CoreFoundation 0x18041acc4 __CFRunLoopDoBlocks + 352 23 CoreFoundation 0x1804153cc __CFRunLoopRun + 812 24 CoreFoundation 0x180414c24 CFRunLoopRunSpecific + 552 25 GraphicsServices 0x19020ab10 GSEventRunModal + 160 26 UIKitCore 0x185ad82fc -[UIApplication _run] + 796 27 UIKitCore 0x185adc4f4 UIApplicationMain + 124 28 SwiftUI 0x1d290b41c closure #1 in KitRendererCommon(_:) + 164 29 SwiftUI 0x1d290b144 runApp<A>(_:) + 84 30 SwiftUI 0x1d266bef4 static App.main() + 148 31 CanvasTest.debug.dylib 0x105061c64 static CanvasTest.$main() + 40 32 CanvasTest.debug.dylib 0x105061d14 __debug_main_executable_dylib_entry_point + 12 (CanvasTest.swift:11) 33 dyld_sim 0x10519d410 start_sim + 20 34 dyld 0x10539a274 start + 2840 Thread 4:: com.apple.uikit.eventfetch-thread 0 libsystem_kernel.dylib 0x1050f5290 mach_msg2_trap + 8 1 libsystem_kernel.dylib 0x1051066c4 mach_msg2_internal + 76 2 libsystem_kernel.dylib 0x1050fd3f4 mach_msg_overwrite + 536 3 libsystem_kernel.dylib 0x1050f55cc mach_msg + 20 4 CoreFoundation 0x18041b000 __CFRunLoopServiceMachPort + 156 5 CoreFoundation 0x180415528 __CFRunLoopRun + 1160 6 CoreFoundation 0x180414c24 CFRunLoopRunSpecific + 552 7 Foundation 0x180f319c8 -[NSRunLoop(NSRunLoop) runMode:beforeDate:] + 208 8 Foundation 0x180f31be8 -[NSRunLoop(NSRunLoop) runUntilDate:] + 60 9 UIKitCore 0x185b858c0 -[UIEventFetcher threadMain] + 404 10 Foundation 0x180f58810 __NSThread__start__ + 720 11 libsystem_pthread.dylib 0x10507f6f8 _pthread_start + 104 12 libsystem_pthread.dylib 0x10507a940 thread_start + 8
Topic: UI Frameworks SubTopic: SwiftUI
0
0
304
Dec ’24
SwiftUI: AlignmentGuide in Overlay not working when in if block
Scenario A SwiftUI view has an overlay with alignment: .top, the content uses .alignmentGuide(.top) {} to adjust the placement. Issue When the content of the overlay is in an if-block, the alignment guide is not adjusted. Example code The example shows 2 views. Not working example, where the content is an if-block. Working example, where the content is not in an if-block Screenshot: https://github.com/simonnickel/FB15248296-SwiftUIAlignmentGuideInOverlayConditional/blob/main/screenshot.png Tested on - Xcode Version 16.0 RC (16A242) on iOS 18.0 Code // Not working .overlay(alignment: .top) { if true { // This line causes .alignmentGuide() to fail Text("Test") .alignmentGuide(.top, computeValue: { dimension in dimension[.bottom] }) } } // Working .overlay(alignment: .top) { Text("Test") .alignmentGuide(.top, computeValue: { dimension in dimension[.bottom] }) } Also created a Feedback: FB15248296 Example Project is here: https://github.com/simonnickel/FB15248296-SwiftUIAlignmentGuideInOverlayConditional/tree/main
0
1
327
Sep ’24
UIWritingToolsCoordinator.Context Lifetime?
What is the lifetime of a UIWritingToolsCoordinator.Context object? The UIWritingToolsCoordinator.Delegate API expects you to maintain a reference to the context identifiers you create in writingToolsCoordinator(:contextsFor:) to be able to return them in writingToolsCoordinator(:rangeInContextWithIdentifierFor:). At some point, you need to release these references. Can you, for example, assume that the context will not be referenced after writingToolsCoordinator(_:willChangeToState:) is called with a state of .inactive?
Topic: UI Frameworks SubTopic: UIKit
0
1
277
Dec ’24
How to use the mouse to select List data items
I have a question about SwiftUI and would like to ask you guys The problem is described as follows I am learning to use SwiftUI. I have a file list display window. I encapsulate the files into a structure called FileInfo and use List to display the files obtained through filemanager. I want to select files by mouse selection. But I didn't find SwiftUI support for selection, so I used Zstack to select, but I found that it is difficult to respond to selection and click events at the same time. Below is my code ZStack { List(selection: $localWorkspaceViewModel.selectedFiles) { ForEach(localWorkspaceViewModel.files.indices, id: \.self) { index in ZStack { } .contextMenu{ // ... } .onTapGesture(count: 2) { // ... } .onTapGesture(count: 1) { // ... } .onDrag { // ... } } .listRowInsets(EdgeInsets()) .listRowSeparator(.hidden) } .contextMenu { // ... } .onDrop(of: ["public.data"], isTargeted: nil) { providers in // ... } Color.clear .contentShape(Rectangle()) .gesture( DragGesture(minimumDistance: 20) .onChanged { value in print() if !isDragging { dragStartPoint = value.startLocation isDragging = true } // ... } .onEnded { _ in isDragging = false } ) .allowsHitTesting(!isDragging) if isDragging { Rectangle() .fill(Color.blue.opacity(0.2)) .frame(width: selectionRect.width, height: selectionRect.height) .position(x: selectionRect.midX, y: selectionRect.midY) .overlay( Rectangle() .stroke(Color.blue, lineWidth: 1) ) .allowsHitTesting(false) } } The code problem is described as follows When the line of code .allowsHitTesting(!isDragging) sets the static value to true or false, the click and drag event of the List item behaves normally or the box selection of Color.clear behaves normally, but only one of them behaves normally. However, after setting it to !isDragging, only one of them behaves normally. I would like to ask how to solve this problem. I would be very grateful if you can give me a solution.
Topic: UI Frameworks SubTopic: SwiftUI
0
0
261
Nov ’24
Glitchy page transitions with TabView on watchOS
We're trying to implement transitions between TabView pages similar to what the Fitness app does on watchOS. As the user swipes or uses the Digital Crown to move between pages, the large rings gauge in the center transitions smoothly to a toolbar item. The code to implement this transition is described in two places in Apple's documentation: https://developer.apple.com/documentation/watchos-apps/creating-an-intuitive-and-effective-ui-in-watchos-10 (See the section “Provide continuity with persistent elements”) The WWDC23 session "Design and build apps for watchOS 10", around 9:30 However, copying the code from Apple's documentation doesn't give animation as reliable as what we're seeing in the Fitness app. Any slight reversal of motion causes the transition animation to jump back to the starting state. Has anyone else figured out how to replicate what the Fitness app is doing on watchOS? I've included our View implementation below. Debug prints show what's going wrong: the page variable decrements immediately the user moves backward by any amount. But somehow, the Fitness app gets around this problem. How? struct ContentView: View { @Namespace var namespace @State var page = 0 var body: some View { NavigationStack { TabView(selection: $page) { globeView .containerBackground(Color.blue.gradient, for: .tabView) .navigationTitle("One") .matchedGeometryEffect( id: "globe", in: namespace, properties: .frame, isSource: page == 0) .tag(0) Text("Page two") .containerBackground(Color.green.gradient, for: .tabView) .navigationTitle("Two") .tag(1) } .tabViewStyle(.verticalPage) .toolbar { ToolbarItem(placement: .topBarLeading) { globeView .matchedGeometryEffect( id: "globe", in: namespace, properties: .frame, isSource: page == 1) } } } } @ViewBuilder var globeView: some View { Image(systemName: "globe") .resizable() .scaledToFit() } } Thanks for any help! —Chris
0
1
343
Sep ’24
Potential Issue in "Display Distinct Layouts Per Section" Documentation Example
Hi everyone, I was exploring the Display Distinct Layouts Per Section section of the Apple documentation and noticed a potential issue in the example code provided. Specifically, in the createLayout method of the TwoColumnViewController in the sample project, the item size appears to be incorrectly described. The documentation states that the item size is ignored because the items are organized in columns, but in practice, the size is considered. When running the sample project without any modifications, the layout doesn't behave as described or expected. Here’s what I observed: The items are not displayed as intended in a two-column layout. Modifying the item size explicitly affects the layout, contrary to the documentation's claim that the size is ignored. This seems to be a mismatch between the documentation and the actual implementation. Could this be clarified or corrected? Has anyone else encountered this issue? If so, are there any recommended adjustments to the sample code to achieve the intended layout? Thanks in advance for any insights or updates on this! https://developer.apple.com/documentation/uikit/views_and_controls/collection_views/implementing_modern_collection_views#4461906
Topic: UI Frameworks SubTopic: UIKit
0
2
255
Nov ’24
SwiftUI context menu scroll broken when view changes
Hi I am on ios 18 and xcode 16 I have a view that changes with a timer and I want to be able to long press that view and show a context menu. However the scroll on the context menu seems to be broken? import SwiftUI struct ContentView: View { @State var number = 0 @State var timer = Timer.publish(every: 0.25, on: .main, in: .common).autoconnect() var body: some View { VStack { Text(number.formatted()) .font(.largeTitle) Text("Long press me") Text("Notice context menu cannot scroll down") } .padding() .background { RoundedRectangle(cornerRadius: 10.0) .fill(Color(uiColor: .secondarySystemBackground)) } .contextMenu { ForEach(0 ..< 100) { index in Button { print("option \(index)") } label: { Label("Option \(index)", systemImage: "globe") } } } .onReceive(timer) { t in number += 1 } } } Is this a bug in swiftUI? In my real application I want the context menu to be able to switch the kind of data the user is viewing.
0
0
319
Sep ’24
Scrolling Table with children in SwiftUI for macOS app
How do I scroll to a row and select it when it is part of collapsed rows in Table ScrollViewReader { scrollViewProxy in Table([node], children: \.children, selection: $selectedNodeID) { TableColumn("Key") { Text($0.key) } TableColumn("Value") { Text($0.val) } } .onChange(of: selectedNodeID) { _, newValue in withAnimation { scrollViewProxy.scrollTo(newValue) } } } The code above works well for the rows that are expanded or at the root level. However, for the rows that are not yet expanded the code above does nothing. How can I update the code so that it scrolls to a row that has not materialized yet. Info: This is a macOS app I am on macOS 15.1.1 with Xcode 16.1 and the minimum target of the app is macOS 15
0
0
369
Nov ’24
iOS 18: "Invalid number of items in section 0"
Hi, I recently started experiencing the following bug in the code listed below. The app is a dieting/calorie logging app with a function that presents a List() of calories in different days, separated into sections for each Meal as derived from an array of Meals. Part of this functionality is that the user can swipe an entry in the List to delete one. If the user has one entry and they delete it, behaviour is as expected. If they have more than one entry and they delete one, behaviour is as expected. If they have more than one entry and they delete two items, one after another, the app crashes with the message "Invalid number of items in section 0". If they have more than one entry and they delete one, then go back to the main screen of the app, then delete another one, behaviour is as expected. Searches online suggest that this is because the array underpinning the list has not updated. However the app crashes before it has even reached the delete() function called by onDelete, so there is no opportunity to update the model before something refreshes and the app crashes. Does anyone have any idea how to resolve this? This code worked fine up until iOS 18. List { if list.budgieData.count != 0 { ForEach(list.mealList.indices, id: \.self) { idx in Section(header: Text(list.mealList[idx].name)) { ForEach(list.budgieData.indices, id: \.self) { entryIdx in if list.budgieData[entryIdx].meal == list.mealList[idx].mealUUID { CalorieEntryView(calories: list.budgieData[entryIdx].calories, narrative: list.budgieData[entryIdx].narrative ?? "Quick calories", realEntry: list.budgieData[entryIdx].realEntry, date: list.budgieData[entryIdx].date) } }.onDelete(perform: delete) } } } else { Text("You have no calories logged in Budgie Diet on this day.") } if list.hkCalories != 0 { Section(header: Text("Calories from other apps"), footer: Text("These are calories logged in Health by other apps. You'll need to go to the app that logged them to change or delete them.")) { CalorieEntryView(calories: list.hkCalories, narrative: "Calories from other apps", realEntry: false, date: list.curDate) .deleteDisabled(true) } } }.listStyle(.grouped)
Topic: UI Frameworks SubTopic: SwiftUI Tags:
0
0
200
Oct ’24