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

Post

Replies

Boosts

Views

Activity

SwiftUI State not reliable updating
Hello, I have a SwiftUI view with the following state variable: @State private var startDate: Date = Date() @State private var endDate: Date = Date() @State private var client: Client? = nil @State private var project: Project? = nil @State private var service: Service? = nil @State private var billable: Bool = false Client, Project, and Service are all SwiftData models. I have some view content that binds to these values, including Pickers for the client/project/service and a DatePicker for the Dates. I have an onAppear listener: .onAppear { switch state.mode { case .editing(let tt): Task { await MainActor.run { startDate = tt.startDate endDate = tt.endDate client = tt.client project = tt.project service = tt.service billable = tt.billable } } default: return } } This works as expected. However, if I remove the Task & MainActor.run, the values do not fully update. The DatePickers show the current date, the Pickers show a new value but tapping on them shows a nil default value. What is also extremely strange is that if tt.billable is true, then the view does update as expected. I am using Xcode 15.4 on iOS simulator 17.5. Any help would be appreciated.
0
0
38
8h
SwiftUI keyboard shortcuts don't become active until view loads
I have a menu bar extra app that includes a sub-menu for lesser used functions. The sub menu implements .keyboardShortcut for a few of the menu items. When the app is first the active app, the keyboard shortcuts only produce a beep UNTIL the sub menu has been accessed. Once the sub-menu has loaded, the keyboard shortcuts work as expected. I should note that the MenuBarExtra is using the .window display mode, if that's important. The submenu appears with a button press within the MenuBarExtra. Is there a method to expose the keyboard shortcuts to the system before the view has loaded?
1
0
34
9h
NavigationStack with NavigationPath triggers multiple init/deinit of views in stack
Hi all, I've noticed some weird behavior when working NavigationStack paired with a NavigationPath, and I'm wondering if it's by design or perhaps a bug. In short: I'm experiencing that every time I push a new view to the NavigationPath, all the previous views appear to init and deinit, which can cause all sorts of problems if you aren't aware of it happening. It's seems like .navigationDestination(for: ) is run once per item in the path that is given to the NavigationStack. So if you add 3 items it'll run 3 times when adding the third view. But the original views and their state are kept. Is this happening because pushing a view to the stack is seen as a state change? And is it intended? The longer explanation: So I'm developing an app in pure SwiftUI and I'm trying to establish a way of navigating through a router / coordinator. I like that my ViewModels can determine when navigation should happen and not the view. E.g. Normally I'd like to prepare some sort of data that should be transferred to the next view. I've prepared an example project which you can use to check out the issue. It's not a full example of my setup, but it's small enough to show what I'm experiencing. It can be found here: https://github.com/Kimnyhuus/NavigationStackDemo The structure is: Router App RootView AppleView + AppleViewModel BananaView + BananaViewModel PearView + PearViewModel So the Router is an ObservableObject that contains a @Published NavigationPath object + functions for adding / removing to / from stack. I've also added an enum here which defines the destinations that the Router can take an navigate to. RootView is setup with a NavigationStack which is setup with the NavigationPath in the parameter: NavigationStack(path: $router.navPath) { ... } RootView also have the router setup as an EnvironmentObject: .environmentObject(router) This enables the other views to interact with the router and push new views to the stack. Each view is initialized with its corresponding VM. The VMs contain nothing other than init and deinit, a variable containing the initialized id + a @Published num which can be set from the view. This is to keep track of the instances in the prints to the console. Each view can navigate to the two other views. You can try and run the project yourselves, but I've made an example of the inits/deinits that happens here. First, I'm navigating from RootView -> AppleView which is expected. The router prints from func navigate(to destination: Destination) that a view has been pushed to the stack. The RootView prints, when .navigationDestination(for: Destination.self) { ...} is triggered, and it says we're navigating to .apple. And then we see that the AppleVM is inited. All like expected. ||| Router: add to navPath: 1 ||| NavStack: Destination .apple ||| Init ☀️: AppleViewModel, id: 879, num: 0 Then I navigate from AppleView -> BananaView and the weird stuff starts happening. We see that a second view has been added to the stack. BananaVM is inited like we'd expect. But then the previous actions seem to run again but with new instances. ||| Router: add to navPath: 2 ||| NavStack: Destination .banana ||| Init ☀️: BananaViewModel, id: 167, num: 0 ||| NavStack: Destination .apple ||| Init ☀️: AppleViewModel, id: 492, num: 0 Then I navigate from BananaView -> PearView and it's continuing. It's now clear that .navigationDestination(for: Destination.self) { ... } is run once per item in the stack. ||| Router: add to navPath: 3 ||| NavStack: Destination .pear ||| Init ☀️: PearViewModel, id: 436, num: 0 ||| NavStack: Destination .banana ||| Init ☀️: BananaViewModel, id: 292, num: 0 ||| NavStack: Destination .apple ||| Init ☀️: AppleViewModel, id: 434, num: 0 ||| Deinit 🔥: AppleViewModel, id: 492, num: 0 Finally I navigate from PearView to AppleView and it's just piling on. ||| Router: add to navPath: 4 ||| NavStack: Destination .apple ||| Init ☀️: AppleViewModel, id: 738, num: 0 ||| NavStack: Destination .pear ||| Init ☀️: PearViewModel, id: 564, num: 0 ||| NavStack: Destination .banana ||| Init ☀️: BananaViewModel, id: 769, num: 0 ||| Deinit 🔥: BananaViewModel, id: 292, num: 0 ||| NavStack: Destination .apple ||| Init ☀️: AppleViewModel, id: 283, num: 0 ||| Deinit 🔥: AppleViewModel, id: 434, num: 0 Navigating back towards the RootView, you can see that it again inits and deinits different instances of the view models. You’ll notice the original ones with state being deinit’ed where it has a number higher than 0 in “num”. ||| Router: rm navPath: 3 ||| NavStack: Destination .banana ||| Init ☀️: BananaViewModel, id: 222, num: 0 ||| Deinit 🔥: BananaViewModel, id: 769, num: 0 ||| NavStack: Destination .pear ||| Init ☀️: PearViewModel, id: 801, num: 0 ||| Deinit 🔥: PearViewModel, id: 564, num: 0 ||| NavStack: Destination .apple ||| Init ☀️: AppleViewModel, id: 173, num: 0 ||| Deinit 🔥: AppleViewModel, id: 283, num: 0 ||| Deinit 🔥: AppleViewModel, id: 738, num: 0 ||| Router: rm navPath: 2 ||| NavStack: Destination .banana ||| Init ☀️: BananaViewModel, id: 26, num: 0 ||| Deinit 🔥: BananaViewModel, id: 222, num: 0 ||| NavStack: Destination .apple ||| Init ☀️: AppleViewModel, id: 744, num: 0 ||| Deinit 🔥: AppleViewModel, id: 173, num: 0 ||| Deinit 🔥: PearViewModel, id: 801, num: 0 ||| Deinit 🔥: PearViewModel, id: 436, num: 3 ||| Router: rm navPath: 1 ||| NavStack: Destination .apple ||| Init ☀️: AppleViewModel, id: 401, num: 0 ||| Deinit 🔥: AppleViewModel, id: 744, num: 0 ||| Deinit 🔥: BananaViewModel, id: 26, num: 0 ||| Deinit 🔥: BananaViewModel, id: 167, num: 2 ||| Router: rm navPath: 0 ||| Deinit 🔥: AppleViewModel, id: 401, num: 0 ||| Deinit 🔥: AppleViewModel, id: 879, num: 1 What is making NavigationStack / .navigationDestination(for: ) run through all the previous items in the stack, every time the state changes in the NavigationPath? I hope it's not too confusing with all the prints :-) Please let me know if I need to add more info.
0
0
44
10h
How to properly add data files into a SwiftData ModelDocument file package
Hi all, I am working on a macOS/iOS sandboxed app with SwiftUI/SwiftData. The app saves its' data into a ModelDocument file. But I want to also save large binary data files into this file. I create the DocumentGroup scene with: DocumentGroup(editing: Entry.self, contentType: .myDocument) { MainWindowView() } In my MainWindowView, I use @Environment(\.documentConfiguration) private var documentConfiguration to get the URL to the user created ModelDocument file URL. When I need to add large binary file into the ModelDocument file, I call a method in my model: func saveReferencedData(_ data: Data, documentURL: URL?) throws { let logger = Logger(subsystem: "saveReferencedData", category: "Asset") if let documentURL { let referencedFileName = "\(entryIdentifier)_\(assetIdentifier).\(assetType)" let tempFileURL = documentURL.appending(components: referencedFileName) if documentURL.startAccessingSecurityScopedResource() { do { try data.write(to: tempFileURL, options: []) } catch { documentURL.stopAccessingSecurityScopedResource() throw AssetFileOperationError.unableToSaveReferenceFile } self.referencedFileLocation = referencedFileName logger.debug("Successfully saved image data to: \(referenceFileURL)") } documentURL.stopAccessingSecurityScopedResource() } else { logger.debug("ERROR! Unable to save referenced image file because document URL is nil.") } } When this method is called, the data file is saved, but immediately I gets this diablog box: If I click on any of the options in the dialog box, the binary data file is removed. I think this is a permission problem and I am not writing to the ModelDocument file correctly. But I can not find any information online to experiment more. Does anyone have experience with a customized ModelDocument file with more data files written into it? Or if you have any insight or advice, it would be greatly appreciated. Thank you so much for reading.
0
0
32
15h
UIAccessibility.Notification concurrency errors with Xcode 16 beta 2
I am running into some Swift 6 concurrency errors that I think are due to an odd oversight in the UIAccessibility Swift interface. There are a number of constants defined in here for various things, most of which are marked "let" (appropriately). However, the constants for notifications in extension UIAccessibility.Notification are all marked as var for some reason. For example: public static var pageScrolled: UIAccessibility.Notification Because it is var, not let, anytime I try to access it, I get a concurrency violation. I am baffled as to how I am supposed to work around this. For example, this line of code: UIAccessibility.post(notification: .pageScrolled, argument: "test") gives the error: "Reference to static property 'pageScrolled' is not concurrency-safe because it involves shared mutable state" I can't for the life of me figure out how to work around this. I guess maybe define my own constant somewhere and suss out the rawValue somehow for now? This really needs to be fixed in the SDK.
4
0
66
16h
SwiftUI List OutlineGroup
Hello, I'm having some difficulties trying to customise a SwiftUI list-detail splitview using List and OutlineGroup: The model used is provided in Apple documentation OutlineGroup. The contentView is struct ContentView: View { @State var itemString = String() var body: some View { HSplitView { MyOutLine(title: "MyOutLine", itemString: $itemString) .frame(width: 200, height: 300 , alignment: Alignment(horizontal: .leading, vertical: .top)) .padding() MyView(itemString: itemString) } } } The left view is struct MyOutLine: View { let title:String @Binding var itemString:String @State private var selection: FileItem? var body: some View { List(selection: $selection) { OutlineGroup(data, children: \.children) { item in Text ("\(item.description)") .onTapGesture { selection = item itemString = item.description } .listRowBackground( selection == item ? Color.gray :nil ) } } .listStyle(.sidebar) .onAppear { itemString = "No selection"} } } The right view is: struct MyView: View { let itemString:String var body: some View { VStack{ Spacer() HStack { Spacer() Text(itemString) Spacer() } Spacer() } } } The result works but I have 2 problems: The selection works but the detail view is updated only when I click the text but not when I click the rest of the row. This results in the detail view not being sync with the list selection. I would like to customise the colour of the selected row but listRowBackground does not seem to work. Is there a way to fix this Thank you in advance Jean Marie
1
0
64
20h
CompositorLayer, Metal and Alert
Hello. I am creating an app for APV in Metal. I have a CompositorLayer that launches a thread. What can I do to detect the environment alert to stop the thread until it is accepted by the user? If I don't stop the thread, I have problems with the hand tracking alert. Thank you.
1
0
66
1d
Correct Collection View "stretchy header" implementation?
Hello, I have the following subclass of UICompositionalCollectionViewLayout to get the stretchy header effect as shown below. It works quite well, but I don't really have an experience with creating custom layouts so I thought I'd ask if maybe my implementation doesn't have some important flaws. I once ran into persistent layout loop crash with this and I am not sure what exactly I changed but it stopped happening. However since I am using this layout on important screen, I would like to make sure there isn't obvious potential for the layout loop crash happening in App Store version. I am particularly unsure about the shouldInvalidateLayout implementation. Originally I was returning true all the time, but decided to change it and only force invalidation for negative content offset which is when my header is supposed to stretch. Here is the full code: final class StretchyCompositionalLayout: UICollectionViewCompositionalLayout { override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? { var attrs = super.layoutAttributesForElements(in: rect) ?? [] guard let collectionView = collectionView else { return attrs } let contentOffset = collectionView.contentOffset.y guard contentOffset < 0 else { return attrs } var newAttributes: UICollectionViewLayoutAttributes? attrs.forEach({ attribute in if attribute.indexPath.section == 0 && attribute.indexPath.item == 0 { let startFrame = attribute.frame newAttributes = attribute.copy() as? UICollectionViewLayoutAttributes let newFrame: CGRect = .init(x: 0, y: contentOffset, width: startFrame.width, height: startFrame.height - contentOffset) newAttributes?.frame = newFrame } }) if let new = newAttributes { attrs.removeAll { attr in return attr.indexPath.section == 0 && attr.indexPath.item == 0 } attrs.insert(new, at: 0) } return attrs } override func layoutAttributesForItem(at indexPath: IndexPath) -> UICollectionViewLayoutAttributes? { guard let attributes = super.layoutAttributesForItem(at: indexPath) else { return nil } let contentOffset = collectionView?.contentOffset.y ?? 1 guard contentOffset < 0 else { return attributes } if indexPath.section == 0 && indexPath.item == 0 { let attributes = attributes.copy() as? UICollectionViewLayoutAttributes ?? attributes let startFrame = attributes.frame let newFrame: CGRect = .init(x: 0, y: contentOffset, width: startFrame.width, height: startFrame.height - contentOffset) attributes.frame = newFrame return attributes } else { return super.layoutAttributesForItem(at: indexPath) } } override func shouldInvalidateLayout(forBoundsChange newBounds: CGRect) -> Bool { let contentOffset = collectionView?.contentOffset.y ?? 1 // There is visual glitch when 0 is used in this condition if contentOffset < 1 { return true } else { return super.shouldInvalidateLayout(forBoundsChange: newBounds) } } } Any feedback welcome!
0
0
66
1d
How to implement UITextItem in custom text view with UITextInput and TextKit2
Hi Apple, I'm implementing a custom text view by conforming to UITextInput and backing it with TextKit2. However, I like the UITextItem feature of the default UITextView. Can I get some guidance on how to reimplement it? Are we looking at overlaying UIMenu buttons? Or some API where I can display a UIMenu at a rect I specify? Hopefully, it is not some kind of private API? Thanks for the help in advance.
0
0
46
1d
Display interactable UI on macOS login screen
We are developing a lightweight VPN client inside a daemon process that will run even when no user session is active on machine. The lightweight VPN runs in machine context and does not require user session. We would like to display some basic diagnosis information about our lightweight client on macOS login window before user is logged into their machine (in case users need that). So, is it possible to display a UI window on login screen with some basic info that user can interact with. If yes, where can I get started? Please note, this is not an authorization plugin. We are just wanting to display info about our process that runs a lightweight VPN client on macOS login screen.
0
0
49
1d
Help, can't use TabView
Hi, I learned swift only a few weeks ago, and im trying to make a TabView in Xcode. But, it shows only one item! I've already made this work in other apps, but I can't get it working here! import SwiftUI struct tabs: View { var body: some View { TabView { ContentView() .tabItem { Image(systemName: "house.circle.fill") Text("Home") Settngs() .tabItem { Image(systemName:"gear.circle.fill") Text("Settings") } } } } } #Preview { tabs() } and also, I checked "settngs()" and its my name
1
0
78
1d
Is it possible to get a swiftUI timer-text to align .trailing?
Please consider simple example below. I am trying to put a timer in the upper right corner of a live activity. I am done, it works, but I'm trying to get the timer to look better. If I take a regular text, I can get it to align properly by adjusting the .frame(), , but for a text with a timer inside it, alignment is ignored from what I can see. Text("Hello").frame(width: 90, alignment: .trailing).border(.red) /*Text(timerInterval: timeRange, countsDown: false) .monospacedDigit().font(.subheadline).frame(width: 90, alignment: .trailing).border(.red)*/ } Is there any way to fix this? Right now, I have a fixed width so that HH:mm:ss will fit, but that doesn't look super great if it's just minutes and seconds for example, there's an empty block to the right
1
0
57
1d
NavigationLink/Picker
I have a form container with a Navigation Stack at the top level. In a section I have a Navigation link followed by Picker(s) . On its own the navigation link works correctly but when a HStack with Text and Picker is added the navlink breaks . When the link is selected the picker list is presented. It seems others have had this issue which is usually solved by adding the NavigationStack , which is already at the top level. Any guidance is appreciated ( or work around - I added a section between the link and picker but that didn't help ) Joel
5
0
68
1d
Saving edited PDFs directly to application from QuickLook
I'm stuck on a problem where I need to be able to have the same editing capabilities as in .quickLookPreview and be able to save the edited file to the application with the "Done" button. So, in nutshell, I need to implement the same functionality many other applications provide including Apple's Files. However with .quickLookPreview I don't get the ability to save edited files directly to the application, and I've had no luck finding help from the internet (thus this question). Perhaps somebody has implemented this before and could give me a lead somewhere? PS. I'm trying to find a solution without any third party libraries
0
0
38
1d
AttributedString (without NS prefix) and Genmoji
My app uses AttributedString for both text formatting and storage using MarkdownDecodableAttributedStringKey. The new API for Genmoji looks very interesting but I don't see an AttributeScope for it. Is it possible to work around this and stick with AttributedString, am I in the wrong room or should I send in an enhancement request via Feedback Assistant? Thanks a lot for your time!
2
0
55
2d
Can I preview "regular" view in widget extension?
Basically, in my widget/live activity, I want to extract reusable views into a separate file with an isolated view and preview. Dummy example below. I cannot do it because it says "missing previewcontext". The only way I've found is to add the view to my main app target, but I don't want to clutter my main app wiews that only exist in my widgets if I can avoid it. Can this be done somehow? Thoughts appreciated. Dummy example (tried with and without "previewLayout": struct StatusActivityView: View { let status: UserStatusData var body: some View { VStack(alignment: .center) { Text("Dummy example") }.background(.blue).padding(5) } } @available(iOS 16.2, *) struct StatusActivityView_Previews: PreviewProvider { static var previews: some View { let status = WidgetConstants.defaultEntry() return StatusActivityView(status: status).previewLayout(.sizeThatFits) } }
2
0
63
2d
iOS DisclosureGroup content clipping
I have a SwiftUI page that I want to simplify by showing basic information by default, and putting the additional info behind a "Details" DisclosureGroup for advanced users. I started by laying out all the components and breaking things into individual Views. These all are laid out and look fine. Then I took several of them and added them inside a DisclosureGroupView. But all of a sudden, the views inside started getting crunched together and the contents of the DisclosureGroup got clipped about 2/3 of the way down the page. The problem I'm trying to solve is how to show everything inside the DIsclosureGroup. The top-level View looks like this: VStack { FirstItemView() SecondView() DetailView() // <- Shows disclosure arrow } Where DetailView is: struct DetailView: View { @State var isExpanded = true var body: some View { GeometryReader { geometry in DisclosureGroup("Details", isExpanded: $isExpanded) { ThirdRowView() Spacer() FourthRowView() VStack { FifthRowWithChartView() CaptionLabelView(label: "Third", iconName: "chart.bar.xaxis") } } } } } The FifthRowWithChartView is half-clipped. One thing that might contribute is that there is a Chart view at the bottom of this page. I've tried setting the width and height of the DisclosureGroup based on the height returned by the GeometryReader, but that didn't do anything. This is all on iOS 17.6, testing on an iPhone 15ProMax. Any tips or tricks are most appreciated.
2
0
76
2d