Provide views, controls, and layout structures for declaring your app's user interface using SwiftUI.

SwiftUI Documentation

Posts under SwiftUI tag

2,337 Posts
Sort by:
Post marked as solved
30 Replies
17k Views
I keep getting a Xcode Previews error in Xcode 12 from a package that imports other packages. As soon as I remove the dependency I'm able to see the SwiftUI preview. I'm only able to use previews in packages that have no dependencies The error I get is: "LoadingError: failed to load library at path...Library not loaded " then it point to the dependency that it could not load in the current package. How can I access Xcode Previews from a package that depends on other packages?
Posted
by
Post not yet marked as solved
5 Replies
14k Views
Creating a simple card game (Set) and I have a function in the model that deals X cards onto the deck. Currently, when I click the deal card button they all show up at once so I added the timer so that they would appear one after another. This gives the error "Escaping closure captures mutating 'self' parameter" Any ideas on what I can fix? mutating func deal(_ numberOfCards: Int) { for i in 0..<numberOfCards { Timer.scheduledTimer(withTimeInterval: 0.3 * Double(i), repeats: false) { _ in if deck.count > 0 { dealtCards.append(deck.removeFirst()) } } } }
Posted
by
Post marked as solved
19 Replies
9.6k Views
On iOS 13 I used to use optional @State properties to adapt views. In my case, the presented view would either create a new object (an assignment) if the state that is passed into it is nil, or edit the assignment if an assignment was passed in. This would be done in the action block of a Button and it worked beautifully. On iOS 14 / Xcode 12 this no longer seems to work. Given the following code which creates a new assignment and passes it into the editor view when the user taps a "New Assignment" button, the value of assignment remains nil. Is anyone else experiencing similar behaviour? struct ContentView: View { &#9;&#9;@Environment(\.managedObjectContext) var context &#9;&#9;@State var assignmentEditorIsPresented = false &#9;&#9;@State var assignment: Assignment? = nil &#9;&#9;var Body: some View { &#9;&#9;&#9;&#9;[...] &#9;&#9;&#9;&#9;Button("New Assignment", action: { &#9;&#9;&#9;&#9;&#9;&#9;self.assignment = Assignment(context: context) &#9;&#9;&#9;&#9;&#9;&#9;self.assignmentEditorIsPresented = true &#9;&#9;&#9;&#9;}) &#9;&#9;&#9;&#9;.sheet(isPresented: assignmentEditorIsPresented) { &#9;&#9;&#9;&#9;&#9;&#9;[...] &#9;&#9;&#9;&#9;} &#9;&#9;} } What's even weirder is that I tried adding a random piece of state, an Int, to this view and modifying it right before the assignment state (between lines 9 and 10) and it didn't change either.
Posted
by
Post not yet marked as solved
7 Replies
8.2k Views
I have been able to ship some image and asset catalogs in a Swift package with success using Xcode 12b1 and Swift 5.3. I am not having so much luck with using a custom .ttf file in a Swift Package. I am loading a .ttf file in the manifest like so: .target( &#9;name: "BestPackage", &#9;dependencies: [], &#9;resources: [ &#9;&#9;.copy("Resources/Fonts/CustomFont.ttf"), &#9;&#9;.process("Resources/Colors.xcassets") &#9;] ), And I noticed that there's no initializer on the Font type in SwiftUI to include an asset from a module. For example, this works: static var PrimaryButtonBackgroundColor: SwiftUI.Color { &#9;Color("Components/Button/Background", bundle: .module) } However, there's no way to specify where a font is coming from. I was hoping that loading it into the module would emit it into the target for use, but no such luck: static var PrimaryButtonFont: Font {   Font.custom("CustomFont", size: 34) } This does not load the font as expected. I'm investigating using a CoreText api to try and trick it into loading, but I feel like there should be an easier way. Any advice?
Posted
by
Post not yet marked as solved
6 Replies
4.7k Views
I want a widget to use the same custom fonts that the containing app uses. I do not want multiple copies of the font files in the app bundle. I put the font files into a framework shared by the app and the widget extension. I have code to register the fonts from the framework bundle using CTFontManagerRegisterGraphicsFont. That works from the app, but it does not work from the widget extension because it requires UIKit. (At least I think that's why it doesn't seem to work from my widget extension.) Widgets cannot run UIKit code. Is there a way to programmatically register the fonts in a widget? If not is there a way I can make a UIAppFonts Info.plist entry point to a framework?
Posted
by
Post not yet marked as solved
12 Replies
5.7k Views
In a simple app with a ScrollView inside a NavigationView, on scroll the content of the scrollView doesn't smoothly transition from its size with navigationBarDisplayMode .large to .inline, but rather makes this a jarring jump. Minimum code to reproduce: struct ContentView: View {     var body: some View {         NavigationView {             ScrollView {                 ForEach(0..<200, id: \.self) { i in                     Text("Row \(i)")                         .frame(maxWidth: .infinity)                 }             }             .navigationTitle("Test")         }     } } The following code produces the desired smooth transition though: struct ContentView: View {     var body: some View {         NavigationView {             List {                 ForEach(0..<200, id: \.self) { i in                     Text("Row \(i)")                 }             }             .navigationTitle("Test")         }     } } I could not replicate the issue using UIKit's UITableViewController inside a UINavigationViewController, nor with a UIScrollView inside a UINavigationViewController. Observed in simulator and on device running iOS 14 public beta (18A5319i), built with Xcode 12.0 beta 2 (12A6163b) on macOS 10.15.5 (19F101).
Posted
by
Post not yet marked as solved
9 Replies
9.1k Views
Hi, I have been trying to use a popover in SwiftUI in Xcode 12 Beta 2&amp;3 and popovers are showing up as sheets. Here is my code: &#9;&#9;@State private var showPopover: Bool = false &#9;&#9;var body: some View { &#9;&#9;&#9;&#9;VStack { &#9;&#9;&#9;&#9;&#9;&#9;Button("Show popover") { &#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;self.showPopover = true &#9;&#9;&#9;&#9;&#9;&#9;}.popover( &#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;isPresented: self.$showPopover, &#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;arrowEdge: .bottom &#9;&#9;&#9;&#9;&#9;&#9;) { Text("Popover") } &#9;&#9;&#9;&#9;} &#9;&#9;} } However, no popover is presented. Instead it's a sheet. I submitted feedback, but I don't see anyone else complaining about it. I want to confirm I'm not the only one.
Posted
by
Post not yet marked as solved
6 Replies
4.8k Views
I have the new iOS 14 VideoPlayer: private let player = AVPlayer(url: Bundle.main.url(forResource: "TL20_06_Shoba3_4k", withExtension: "mp4")!) &#9;&#9;var body: some View { &#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;VideoPlayer(player: player) &#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;.aspectRatio(contentMode: .fill) ... This player setup can not display 4:3 video on 16:9 screen of tv without black stripes. Modifier aspectRatio does not work on VideoPlayer. How can I set videoGravity of existed AVPlayerLayer to resizeAspectFill via SwiftUI API?
Posted
by
Post not yet marked as solved
8 Replies
14k Views
I need a scrolling view to report when it's scroll/drag gesture ends. Here's a simple SwiftUI example taking a basic approach: import SwiftUI struct CarouselView: View {   let colors: [Color] = [.red, .green, .blue]   var drag: some Gesture {     DragGesture()       .onChanged { state in         print("changing")       }       .onEnded { state in         print("ended")     }   }   var body: some View {     ScrollView(.horizontal, showsIndicators: false) {       HStack {         ForEach(0..<10) { i in           Text("Block \(i)")             .frame(width: 300, height: 300)             .background(colors[i % colors.count])             .id(i)         }       }     }       .gesture(drag)   } } The gesture's events properly fire when you drag vertically, but when you drag horizontally (matching the direction of the scroll view) only the first onChanged event fires. I don't want to even begin trying to reimplement a ScrollView in SwiftUI just to get these events, but is there a better way?
Posted
by
Post not yet marked as solved
1 Replies
686 Views
I have a NSTableView under a NSViewRepresentable and I'm trying to add a new row when the + button is clicked. With the code below, the ForEach statement is updated when the data is added to the state variable, but the table view doesn't show the new element. Why is that? import PlaygroundSupport import SwiftUI struct TV: NSViewRepresentable {   @Binding var students: Array&lt;String&gt;       func makeNSView(context: Context) -> NSScrollView {     let sv = NSScrollView()     let tv = NSTableView()     sv.documentView = tv     tv.gridStyleMask = .solidHorizontalGridLineMask     tv.usesAlternatingRowBackgroundColors = true//     tv.allowsMultipleSelection = true     let col = NSTableColumn(identifier: NSUserInterfaceItemIdentifier(rawValue: "Name"))     col.title = "Name"     _ = tv.addTableColumn(col)           _ = tv.delegate = context.coordinator     tv.dataSource = context.coordinator     return sv   }   func updateNSView(_ nsView: NSScrollView, context: Context) {     (nsView.documentView as! NSTableView).reloadData()   }   func makeCoordinator() -> Coordinator {     Coordinator(self, students: self._students)   }         class Coordinator: NSObject, NSTableViewDelegate, NSTableViewDataSource {     var parent: TV     @Binding var students: Array&lt;String&gt;     init(_ parent: TV, students: Binding&lt;Array<String&gt;>) {       self.parent = parent       self._students = students     }     func numberOfRows(in tableView: NSTableView) -> Int {       return students.count     }     func tableView(_ tableView: NSTableView, objectValueFor tableColumn: NSTableColumn?, row: Int) -> Any? {       print(students[row])       return students[row]     }     func tableView(_ tableView: NSTableView, shouldEdit tableColumn: NSTableColumn?, row: Int) -> Bool {       return true     }     func tableView(_ tableView: NSTableView, setObjectValue object: Any?, for tableColumn: NSTableColumn?, row: Int) {       self.students[row] = object as! String     }   } } struct view: View {   @State var students = ["John", "Mary", "Bob"]   @State var minusDisabled: Bool = true       var body: some View {     Group {       VStack(alignment: .leading) {         Text("Test")         TV(students: self.$students).frame(width: 400, height: 300)         HStack {           Button(action: {             self.students.append("New Row")           }) {             Text("+")             }.buttonStyle(BorderedButtonStyle())           Button(action: {           }) {             Text("-")           }.buttonStyle(BorderedButtonStyle())           .disabled(self.minusDisabled)         }       }.fixedSize()       ForEach(self.students, id: \.self) { student in         Text(student)       }     }   } } PlaygroundPage.current.setLiveView(view().frame(width: 500, height: 800))
Posted
by
Post not yet marked as solved
2 Replies
2.1k Views
I have a ZStack with two nested views. They are both the same type, RowView, and each RowView has another ZStack and a Text. Both of these RowViews have the same height for some reason. And when I replace the RowView ZStack with just a Text, it works correctly. import SwiftUI struct ContentView: View {     var body: some View {         ScrollView { &amp;#9;&amp;#9; // remove this ZStack and things work with the other nested ZStacks             ZStack {                 Rectangle()                     .foregroundColor(.blue)                     .shadow(radius: 5, x: 5, y: 5)                                  VStack {                     // Two independent RowViews:                                          RowView(title: "Some really long text for some stuff lollola really long text for some stuff lollola")                                          RowView(title: "and more")                 }             }             .padding()         }     } } struct ContentView_Previews: PreviewProvider {     static var previews: some View {         ContentView()     } } struct RowView: View {     @State var title: String          let boxSize: CGFloat = 40          var body: some View {         HStack(alignment: .top, spacing: nil) {             Rectangle()                 .foregroundColor(.orange)                 .frame(minWidth: boxSize,                        maxWidth: boxSize,                        minHeight: boxSize,                        maxHeight: boxSize)                 .padding(5)                          // this has each RowView set its own height correctly //            Text(title) //                .multilineTextAlignment(.leading) //                .padding(5)             // this forces both RowViews to have the same height, even though they are separate from each other             ZStack {                 Rectangle()                     .foregroundColor(.gray)                                  Text(title)                     .multilineTextAlignment(.leading)                     .padding(5)             }             .padding(5)             // this also forces both RowViews to have the same height //            Rectangle() //                .foregroundColor(.gray) //                .overlay(Text(title).padding()) //                .padding(5)         }     } } It seems strange that both independent RowViews will end up having the same height. Read the release notes and didn't see mention of this being a possible bug. Copy pasta and see the results if you'd like. Notice the Gray ZStack containers are all almost the same height? Make the test of the first row even longer. Notice how the second one increases it's height? Is this a bug,? Are ZStacks never supposed to be nested?
Posted
by
Post not yet marked as solved
3 Replies
2.3k Views
I'm using a NavigationView to display "split view" style sidebar and secondary views similar to the Fruta sample app. My sidebar has a List of NavigationLink's, and my secondary view displays that linked content. However, I'm not able to set an initial "default" selection (i.e. blue background selected row style) for the List in my sidebar. When the app first launches, there's no selection state in the List for the secondary view that is displayed until the user taps a row of the List. I have a @State var called selection that's passed into my Sidebar, which references it as a @Binding. selection has a value, which is why it's unexpected that the resulting List doesn't show it as selected when first displayed. EXPECTED RESULTS When the app launches, I would expect the List selects the initial row matching the @Binding that's passed in. ACTUAL RESULTS When the app launches, The List has no initial selected row until the user taps a row. I'd like for the user to launch into the app with a Sidebar List row already selected, similar to the way the Shortcuts app does when launched. How do I enable this kind of behavior? Here's full demo code – iOS 14 beta 4, iPad in landscape: import SwiftUI @main struct SidebarSelectionApp: App { &#9;&#9;var body: some Scene { &#9;&#9;&#9;&#9;WindowGroup { &#9;&#9;&#9;&#9;&#9;&#9;ContentView() &#9;&#9;&#9;&#9;} &#9;&#9;} } enum NavigationItem: Int, Identifiable { &#9;&#9;var id: Int { return self.rawValue } &#9;&#9;case view1 &#9;&#9;case view2 &#9;&#9;case view3 } struct ContentView: View { &#9;&#9;@State var selection: NavigationItem? = .view1 &#9;&#9;var body: some View { &#9;&#9;&#9;&#9;Sidebar(selection: $selection) &#9;&#9;} } struct Sidebar: View { &#9;&#9;@Binding var selection: NavigationItem? &#9;&#9;var body: some View { &#9;&#9;&#9;&#9;NavigationView { &#9;&#9;&#9;&#9;&#9;&#9;list &#9;&#9;&#9;&#9;&#9;&#9;EmptyView() &#9;&#9;&#9;&#9;} &#9;&#9;} &#9;&#9;var list: some View { &#9;&#9;&#9;&#9;List(selection: $selection) { &#9;&#9;&#9;&#9;&#9;&#9;NavigationLink( &#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;destination: View1(), &#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;tag: NavigationItem.view1, &#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;selection: $selection, &#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;label: { &#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;Text("View 1") &#9;&#9;&#9;&#9;&#9;&#9;}) &#9;&#9;&#9;&#9;&#9;&#9;NavigationLink( &#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;destination: View2(), &#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;tag: NavigationItem.view2, &#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;selection: $selection, &#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;label: { &#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;Text("View 2") &#9;&#9;&#9;&#9;&#9;&#9;}) &#9;&#9;&#9;&#9;&#9;&#9;NavigationLink( &#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;destination: View3(), &#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;tag: NavigationItem.view3, &#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;selection: $selection, &#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;label: { &#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;Text("View 3") &#9;&#9;&#9;&#9;&#9;&#9;}) &#9;&#9;&#9;&#9;} &#9;&#9;&#9;&#9;.listStyle(SidebarListStyle()) &#9;&#9;&#9;&#9;.navigationTitle("List") &#9;&#9;} } struct View1: View { &#9;&#9;var body: some View { &#9;&#9;&#9;&#9;Text("This is View 1").font(.title).foregroundColor(.green) &#9;&#9;} } struct View2: View { &#9;&#9;var body: some View { &#9;&#9;&#9;&#9;Text("This is View 2").font(.title).foregroundColor(.blue) &#9;&#9;} } struct View3: View { &#9;&#9;var body: some View { &#9;&#9;&#9;&#9;Text("This is View 3").font(.title).foregroundColor(.red) &#9;&#9;} }
Posted
by
Post not yet marked as solved
6 Replies
2.2k Views
I have recently created a pure (admittedly simple) SwiftUI app for iOS/iPad. Yes there are bugs and limitations I've had to face but eventually with a certain amount of compromise and without resorting to UIViewRepresentable, it works adequately. Great, I thought, how hard can it be to create a macOS version of the same app? Take TextField (swiftUI) views which my app depends on a lot, the issues I have found have been numerous... TextField does not appear to update the Binded variable after each character is typed in. You have to hit the return key for it to register. Totally different functionality. Placeholder text shifts up a few pixels when it gets keyboard focus. The rectangle where the text is typed needs to be taller holding the text, currently it looks squashed. Manually adding a ‘clear text’ button on top of the TextField (at the right) appears not to to be active when the cursor is over it (most of the time) Lots of missing autocapitalisation type functionality is missing. I could go back to a NSViewRepesentable solution of the TextField but that negates the use of 'supported' SwiftUI features. Has this half baked feature been pushed out there as a 'tick in the box' option or is Apple genuinely happy with their solution? Anyhow, I thought let's do a MacCatalyst version of my App instead. But we get a TabView looking like a iPad/iPhone App, there is no option to make it look more mac like AFAIS without abandoning TabView itself! Then there's the complication of making my Core Data App work as a 'Document Based' app with the new DocumentGroup/Scene solution.... how does NSPersistentDocument work in such scenarios? The documentation is vague at best, or simply not supported without a lot of workarounds. Just these few things make me feel we are being hyped with solutions which are far too premature for any real world work on macOS at the moment. What potential SwiftUI/macOS blockers have you encountered?
Posted
by
Post not yet marked as solved
2 Replies
3.9k Views
I am working with a ScrollView and a LazyVStack that can have many rows, sometimes 500 or more. My rows are expandable on tap. Performance of expand/collapse is unacceptable when the number of rows exceeds 100. The more rows, the more performance degrades. This is the gist of my code: struct PlaceView: View { &#9;&#9;/* ... */ &#9;&#9;var place: Place &#9;&#9;@Binding expandedPlaceId: Int &#9;&#9;var content: some View { &#9;&#9;&#9;&#9;VStack(alignment: .leading) { &#9;&#9;&#9;&#9;&#9;&#9;Text(place.name) &#9;&#9;&#9;&#9;&#9;&#9; &#9;&#9;&#9;&#9;&#9;&#9;if self.expandedPlaceId.wrappedValue == place.id { &#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;VStack(alignment: .leading) { &#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;Text(place.city) &#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;} &#9;&#9;&#9;&#9;&#9;&#9;} &#9;&#9;&#9;&#9;} &#9;&#9;} } struct PlacesListView: View { &#9;&#9;/*...*/ &#9;&#9;@State expandedPlaceId = -1 &#9;&#9;var body: some View { &#9;&#9;&#9;ScrollView { &#9;&#9;&#9;&#9;LazyVStack { &#9;&#9;&#9;&#9;&#9;ForEach(places, id: \.id) { place in &#9;&#9;&#9;&#9;&#9;&#9;PlaceView(place: place, expandedPlaceId: self.$expandedPlaceId) &#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;.onTapGesture { self.selectDeselect(place) } &#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;.animation(.linear(duration: 0.3)) &#9;&#9;&#9;&#9;&#9;} &#9;&#9;&#9; } &#9;&#9; } &#9;} } I created an init function in PlaceView with the following: print("calling int for place \(place.id)") What I have noticed is when expanding, every single PlaceView calls init. For 20 or 30 PlaceView rows this is not a problem, but with several hundred views this creates a choppiness in animation and delays the expansion of the detail section. Is there any workaround for this problem? It does not matter if I use LazyVStack or VStack (which itself is unexpected). Here is an example project that can easily be modified to highlight the problem: https://github.com/V8tr/ExpandableListSwiftUI In the above project, simply add the following to PlaceView.swift init(place: Place, isExpanded: Bool) {         self.place = place         self.isExpanded = isExpanded         print("PlaceView init \(self.place.id)") }
Posted
by
Post not yet marked as solved
7 Replies
2.5k Views
In WatchOS 6 a presented .sheet could be dismissed by swiping down or tapping on the navigationBarTitle. In the WatchOS 7 beta, presented sheets are no longer dismissible by either method...forcing the addition of a button to dismiss. It appears as if .sheet is now acting as .fullScreenCover within WatchOS 7. Anyone else running into this? Wondering if this is now expected behavior on WatchOS or if it's a bug...
Posted
by
Post not yet marked as solved
11 Replies
14k Views
I am presenting a sheet using the view modifier .sheet(item: ...) if the view you are presenting is wrap inside another view which only add a navigation view let's say I have a view called ViewB with a dismiss button which called the presentation mode dismiss, that works let' say I have another view called ViewBWithNavigationView where it's calling ViewB inside the NavigationView and it also calling dismiss on the cancel button the result of this is that the presentation mode dismiss will only works for the first view B the cancel button, it will no close the view if you click the button inside the view struct ViewBInsideNavigationView: View {       @Environment(\.presentationMode) var presentationMode   var body: some View {     NavigationView {       ViewB()         .navigationBarTitle("View B", displayMode: .inline)         .navigationBarItems(leading: Button("Cancel") {           self.presentationMode.wrappedValue.dismiss()         })     }   } } the call to self.presentationMode.wrappedValue.dismiss() inside ViewB is not trigger and the view is not dismiss thanks
Posted
by
Post not yet marked as solved
8 Replies
7.8k Views
The two property wrappers @AppStorage and @SceneStorage are great because you can simply redeclare a property in multiple views to share the value and automatically update other views. But how should I access those same values outside of views? I have helper functions which are used in multiple views and which change behaviour based on those stored properties. I believe I could use the old NSUserDefaults.standard to reference the @AppStorage values, but is that the "right" way to do it, and how do I access @SceneStorage values?
Posted
by