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
How does the widget in iOS17 configure this kind of page?
I tried to use AppIntentConfiguration in iOS17 to fail to achieve such a dynamic configuration. code: struct ConfigurationAppIntent: WidgetConfigurationIntent {     static var title: LocalizedStringResource { "位置" }     static var description: IntentDescription { "选择位置以展示城市天气" }     @Parameter(title: "Select City", optionsProvider: CityOptionsProvider())     var selectedCity: String? }
Topic: UI Frameworks SubTopic: SwiftUI
0
0
166
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
How to determine which ui control is found first in the view hierarchy, when I assign the same keyboardShortcut () to 2 buttons?
import SwiftUI struct ContentView: View { var body: some View { VStack { Button ("Button 1") { print ("Button 1"); } .keyboardShortcut("k", modifiers: .command) Button ("Button 2") { print ("Button 2"); } .keyboardShortcut("k", modifiers: .command) } } } I the above snippet, I have assigned the same keyboard shortcut (cmd +k) to 2 different buttons. According to the docs, if multiple controls are associated with the same shortcut, the first one found is used. How do I figure out if Button 1 would be found first during the traversal or Button 2 ? Is it based on the order of declaration? Is it always the case that Button 1 would be found first since it was declared before Button 2 ?
0
0
94
Mar ’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 Tabview - how to "kill" the views we do not use
I have the MainView as the active view if the user is logged in(authenticated). the memory allocations when we run profile is pretty good. We have graphql fetching, we have token handling eg: This is All heap: 1 All Heap & Anonymous VM 13,90 MiB 65408 308557 99,10 MiB 373965 Ratio: %0.14, %0.86 After what i have checked this is pretty good for initialise and using multiple repositories eg. But when we change tabs: 1 All Heap & Anonymous VM 24,60 MiB 124651 543832 156,17 MiB 668483 Ratio: %0.07, %0.40 And that is not pretty good. So i guess we need to "kill" it or something. How? I have tried some techniques in a forum this was a recommended way: public struct LazyView<Content: View>: View { private let build: () -> Content @State private var isVisible = false public init(_ build: @escaping () -> Content) { self.build = build } public var body: some View { build() Group { if isVisible { build() } else { Color.clear } } .onAppear { isVisible = true } .onDisappear { isVisible = false } } } But this did not help at all. So under here is the one i use now. So pleace guide me for making this work. import DIKit import CoreKit import PresentationKit import DomainKit public struct MainView: View { @Injected((any MainViewModelProtocol).self) private var viewModel private var selectedTabBinding: Binding<MainTab> { Binding( get: { viewModel.selectedTab }, set: { viewModel.selectTab($0) } ) } public init() { // No additional setup needed } public var body: some View { NavigationStack(path: Binding( get: { viewModel.navigationPath }, set: { _ in } )) { TabView(selection: selectedTabBinding) { LazyView { FeedTabView() } .tabItem { Label("Feed", systemImage: "house") } .tag(MainTab.feed) LazyView { ChatTabView() } .tabItem { Label("Chat", systemImage: "message") } .tag(MainTab.chat) LazyView { JobsTabView() } .tabItem { Label("Jobs", systemImage: "briefcase") } .tag(MainTab.jobs) LazyView { ProfileTabView() } .tabItem { Label("Profile", systemImage: "person") } .tag(MainTab.profile) } .accentColor(.primary) .navigationDestination(for: MainNavigationDestination.self) { destination in switch destination { case .profile(let userId): Text("Profile for \(userId)") case .settings: Text("Settings") case .jobDetails(let id): Text("Job details for \(id)") case .chatThread(let id): Text("Chat thread \(id)") } } } } } import SwiftUI public struct LazyView<Content: View>: View { private let build: () -> Content public init(_ build: @escaping () -> Content) { self.build = build } public var body: some View { build() } }
0
0
194
Mar ’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
238
Jan ’25
SwiftUI @Observable Causes Extra Initializations When Using Reference Type Properties
I've encountered an issue where using @Observable in SwiftUI causes extra initializations and deinitializations when a reference type is included as a property inside a struct. Specifically, when I include a reference type (a simple class Empty {}) inside a struct (Test), DetailsViewModel is initialized and deinitialized twice instead of once. If I remove the reference type, the behavior is correct. This issue does not occur when using @StateObject instead of @Observable. Additionally, I've submitted a feedback report: FB16631081. Steps to Reproduce Run the provided SwiftUI sample code (tested on iOS 18.2 & iOS 18.3 using Xcode 16.2). Observe the console logs when navigating to DetailsView. Comment out var empty = Empty() in the Test struct. Run again and compare console logs. Change @Observable in DetailsViewModel to @StateObject and observe that the issue no longer occurs. Expected Behavior The DetailsViewModel should initialize once and deinitialize once, regardless of whether Test contains a reference type. Actual Behavior With var empty = Empty() present, DetailsViewModel initializes and deinitializes twice. However, if the reference type is removed, or when using @StateObject, the behavior is correct (one initialization, one deinitialization). Code Sample import SwiftUI enum Route { case details } @MainActor @Observable final class NavigationManager { var path = NavigationPath() } struct ContentView: View { @State private var navigationManager = NavigationManager() var body: some View { NavigationStack(path: $navigationManager.path) { HomeView() .environment(navigationManager) } } } final class Empty { } struct Test { var empty = Empty() // Comment this out to make it work } struct HomeView: View { private let test = Test() @Environment(NavigationManager.self) private var navigationManager var body: some View { Form { Button("Go To Details View") { navigationManager.path.append(Route.details) } } .navigationTitle("Home View") .navigationDestination(for: Route.self) { route in switch route { case .details: DetailsView() .environment(navigationManager) } } } } @MainActor @Observable final class DetailsViewModel { var fullScreenItem: Item? init() { print("DetailsViewModel Init") } deinit { print("DetailsViewModel Deinit") } } struct Item: Identifiable { let id = UUID() let value: Int } struct DetailsView: View { @State private var viewModel = DetailsViewModel() @Environment(NavigationManager.self) private var navigationManager var body: some View { ZStack { Color.green Button("Show Full Screen Cover") { viewModel.fullScreenItem = .init(value: 4) } } .navigationTitle("Details View") .fullScreenCover(item: $viewModel.fullScreenItem) { item in NavigationStack { FullScreenView(item: item) .navigationTitle("Full Screen Item: \(item.value)") .toolbar { ToolbarItem(placement: .cancellationAction) { Button("Cancel") { withAnimation(completionCriteria: .logicallyComplete) { viewModel.fullScreenItem = nil } completion: { var transaction = Transaction() transaction.disablesAnimations = true withTransaction(transaction) { navigationManager.path.removeLast() } } } } } } } } } struct FullScreenView: View { @Environment(\.dismiss) var dismiss let item: Item var body: some View { ZStack { Color.red Text("Full Screen View \(item.value)") .navigationTitle("Full Screen View") } } } Console Output With var empty = Empty() in Test DetailsViewModel Init DetailsViewModel Init DetailsViewModel Deinit DetailsViewModel Deinit Without var empty = Empty() in Test DetailsViewModel Init DetailsViewModel Deinit Using @StateObject Instead of @Observable DetailsViewModel Init DetailsViewModel Deinit Additional Notes This issue occurs only when using @Observable. Switching to @StateObject prevents it. This behavior suggests a possible issue with how SwiftUI handles reference-type properties inside structs when using @Observable. Using a struct-only approach (removing Empty class) avoids the issue, but that’s not always a practical solution. Questions for Discussion Is this expected behavior with @Observable? Could this be an unintended side effect of SwiftUI’s state management? Are there any recommended workarounds apart from switching to @StateObject? Would love to hear if anyone else has run into this or if Apple has provided any guidance!
0
0
326
Feb ’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
403
Jan ’25
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
Stage Manager - UIWindowScene sizeRestrictions on iPad
Hello everyone, The setup: I have an iPadOS app. The app does not require full screen (Requires full screen option is disabled). The problem: The app starts looking unpolished when the canvas becomes too small. What I tried: I am trying to limit the canvas size for our app when run in Stage Manager. How: I saw that UIWindowScene has sizeRestrictions. This property is not always set as per documentation: https://developer.apple.com/documentation/uikit/uiwindowscene/sizerestrictions From my experiments, it only works when it's run on MacOS (in compatibility mode in our case). Console logs: Stage Manager - Requires full screen - OFF willConnectToSession - sizeRestrictions: nil sceneDidBecomeActive - sizeRestrictions: nil Stage Manager - Requires full screen - ON willConnectToSession - sizeRestrictions: nil sceneDidBecomeActive - sizeRestrictions: nil Stage Manager - Requires full screen - OFF - RUN on MacOS willConnectToSession - sizeRestrictions: Available sceneDidBecomeActive - sizeRestrictions: Available Question: Is there a way to enforce this minimum canvas size?
Topic: UI Frameworks SubTopic: UIKit
0
0
75
Mar ’25
Magnification Gesture conflicts with UIPageViewController scroll gesture
The Problem I am trying to implement a pinch-to-zoom feature on images within a UIPageViewController. However, often times when trying to pinch to zoom, the magnification gesture gets overridden by the scrolling gesture built into the UIPageViewController. I'm not sure how to get around this. The Apple Photos app seems to allow pinch to zoom on photos inside a full-page scrolling view without any issue, so I believe it should be possible. Versions: iOS 17.2.1 - iOS 18.2.1, Swift (SwiftUI), Xcode 15.1 Steps to Reproduce Run this sample Xcode project on a physical device: https://drive.google.com/file/d/1tB1QyY6QPEp-WLzdHxgDdkM45xCAELLr/view?usp=share_link Try pinching to zoom on the image. After a few goes at it, you'll likely find that one time it will scroll instead of pinching to zoom. It might take up to a dozen pinches to experience this issue. What I've Tried Making the magnification gesture a high priority gesture. Having only one page in the paging view controller. Subclassing UIScrollView and conforming to the UIGestureRecognizerDelegate in that subclass, as explained here: https://stackoverflow.com/a/51070947/12218938 Using the iOS 17 ScrollView instead. Unfortunately it has the same issue but even worse! It's possible that since this is a native SwiftUI view, people might have solutions to this, but from a brief search I couldn't find any. If you set the data source to nil (which indicates that there are no other pages for the paging view controller to scroll to), it does work, but it's not a workable solution since the time you'd want to set the data source to nil is when the user pinches the screen, but you can't know when the user pinches the screen if the gesture doesn't work! Other Ideas/Workarounds We could have some "zoom" mode that temporarily cancels the ability to scroll while zooming. But this seems like not too nice/intuitive of a solution. If there is no paging view that Apple provides which could be made compatible with a pinch-to-zoom gesture, it's possible we would have to make a completely custom paging view. But that would be a lot of work I presume, so it's probably not something we would have time for right now.
0
0
440
Jan ’25
Animation Issue: SwiftUI View Not Animating Height Changes in UIHostingController
Hello, I’m developing an app where I display a SwiftUI view inside a UIHostingController embedded within a UIKit ViewController. I’m trying to animate the height of the UIHostingController’s view based on a switch’s value, but the SwiftUI view doesn’t animate at all. Below is a simplified version of my code: class ViewController: UIViewController { private lazy var parentView: UIView = { let view = UIView() view.backgroundColor = .red view.translatesAutoresizingMaskIntoConstraints = false return view }() private lazy var hostingView: UIView = { let testView = TestView() let hostingController = UIHostingController(rootView: testView) let view = hostingController.view! view.translatesAutoresizingMaskIntoConstraints = false return view }() private lazy var button: UISwitch = { let button = UISwitch() button.addTarget(self, action: #selector(onClickSwitch(sender:)), for: .valueChanged) button.translatesAutoresizingMaskIntoConstraints = false return button }() private var hostingViewHeightConstraint: NSLayoutConstraint? override func viewDidLoad() { super.viewDidLoad() view.addSubview(parentView) parentView.addSubview(hostingView) parentView.addSubview(button) NSLayoutConstraint.activate([ parentView.topAnchor.constraint(equalTo: view.topAnchor), parentView.bottomAnchor.constraint(equalTo: view.bottomAnchor), parentView.leadingAnchor.constraint(equalTo: view.leadingAnchor), parentView.trailingAnchor.constraint(equalTo: view.trailingAnchor) ]) NSLayoutConstraint.activate([ hostingView.bottomAnchor.constraint(equalTo: parentView.bottomAnchor), hostingView.leadingAnchor.constraint(equalTo: parentView.leadingAnchor), hostingView.trailingAnchor.constraint(equalTo: parentView.trailingAnchor) ]) hostingViewHeightConstraint = hostingView.heightAnchor.constraint(equalTo: parentView.heightAnchor, multiplier: 0.5) hostingViewHeightConstraint?.isActive = true NSLayoutConstraint.activate([ button.centerXAnchor.constraint(equalTo: parentView.centerXAnchor), NSLayoutConstraint(item: button, attribute: .centerY, relatedBy: .equal, toItem: parentView, attribute: .centerY, multiplier: 0.25, constant: 0) ]) } @objc func onClickSwitch(sender: UISwitch) { hostingViewHeightConstraint?.isActive = false let multiplier: CGFloat = sender.isOn ? 0.25 : 0.5 hostingViewHeightConstraint = hostingView.heightAnchor.constraint(equalTo: parentView.heightAnchor, multiplier: multiplier) hostingViewHeightConstraint?.isActive = true UIView.animate(withDuration: 0.3) { self.view.layoutIfNeeded() } } } I’m looking for the behavior demonstrated in the video below: Does anyone have suggestions on how to achieve this?
0
1
178
Mar ’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
MVVM design and data dependency
According to the MVVM design pattern, one of my views depends on many properties in my model. Can I use logic like @published var model = MyModel()? Will there be a large performance loss? Will the UI be refreshed when other unrelated properties in the model are modified? What is the best practice in this case?
Topic: UI Frameworks SubTopic: General
0
0
240
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
MacOS Scale to view
on iOS you can choose to scale to view to have the app resize the screen easily in the developer environment. Scale to view is however not easily done on MacOS using NS to solve on MacOS now. Is it possible for the Apple developer team to make this easier for the Developer, as I understand it is for iOS applications?
0
0
261
Feb ’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