I'm just starting to learn SwiftUI, so I decided to work thru Apple's tutorial, using the latest Xcode (12.5). One line of code immediately got me a semantic error: "Value of type 'Color' has no member 'accessibleFontColor'"Here's the entire source module:
//
// CardView.swift
// Scrumdinger
//
// Created by Vacuumhead on 6/4/21.
//
import SwiftUI
struct CardView: View {
let scrum: DailyScrum
var body: some View {
VStack(alignment: .leading) {
Text(scrum.title).font(.headline)
Spacer()
HStack {
Label("\(scrum.attendees.count)", systemImage: "person.3")
.accessibilityElement(children: .ignore)
.accessibilityLabel(Text("Attendees"))
.accessibilityValue(Text("\(scrum.attendees.count)"))
Spacer()
Label("\(scrum.lengthInMinutes)", systemImage: "clock")
.padding(.trailing, 20)
.accessibilityElement(children: .ignore)
.accessibilityLabel(Text("Meeting length"))
.accessibilityValue(Text("\(scrum.lengthInMinutes) minutes"))
}
.font(.caption)
}
.padding()
.foregroundColor(scrum.color.accessibleFontColor)
}
}
struct CardView_Previews: PreviewProvider {
static var scrum = DailyScrum.data[0]
static var previews: some View {
CardView(scrum: scrum)
.background(scrum.color)
.previewLayout(.fixed(width: 400, height: 60))
}
}
The line that gets the error is the last line of body:
.foregroundColor(scrum.color.accessibleFontColor)
The message is "Value of type 'Color' has no member 'accessibleFontColor'".The program compiles and runs just fine when I comment out that line, of course without any color. I've been writing C++ since the age of dinosaurs but I'm new to SwiftUI and don't even know where I should look to fix this.
Any suggestions are welcome.
There's a file that you're probably missing in the sample project called Color+Codable.swift that defines some extensions on Color. One is accessibleFontColor:
extension Color {
var accesibleFontColor : Color {
//etc.
}
}
Download the files from https://developer.apple.com/tutorials/app-dev-training/managing-state-and-life-cycle and make sure that you're using Color+Codable.swift in your project.
Related
I'm trying to replicate a common view that I've seen in the iPhone settings where you can see some settings field and underneath it, there's an explanation text:
I can't find a way to add the explanation text below and make it look neat like Apple are doing:
struct SomeView: View {
#State private var someBool = true
var body: some View {
Form {
Toggle("I am a toggle", isOn: $someBool)
Text("This is not formatted well :(")
.font(.caption)
.foregroundColor(.gray)
}
.navigationBarTitle(Text("Some form"))
.navigationBarTitleDisplayMode(.inline)
}
}
Here's the result:
Use section footer for that, like
Form {
Section {
Toggle("I am a toggle", isOn: $someBool)
} footer: {
Text("This is not formatted well :(") // << here !!
.font(.caption)
.foregroundColor(.gray)
}
}
Tested with Xcode 13.4 / iOS 15.5
Im trying to make Augmented Reality app with RealityKit but ContentView.swift I have some problems
What is missing here ?` You can see errors on picture which I shared. I followed some tutorial so Im new on Xcode and Realitykit.
Failed to produce diagnostic for expression; please file a bug report
Cannot find 'PlacementButtonsView' in scope
import SwiftUI
import RealityKit
struct ContentView : View {
var models: [String] = {
let filemanager = FileManager.default
guard let path = Bundle.main.resourcePath, let files = try?
filemanager.contentsOfDirectory(atPath:path) else
{ return[]
}
var avaliableModels: [String] = []
for filename in files where filename.hasSuffix("usdz") {
let modelName = filename.replacingOccurrences(of: ".usdz", with: "")
avaliableModels.append(modelName)
}
return avaliableModels
}()
var body: some View {
ZStack(alignment: .bottom) {
ARViewContainer()
ModelPickerView(models: self.models)
PlacementButtonsView()
}
}
}
struct ARViewContainer: UIViewRepresentable {
func makeUIView(context: Context) -> ARView {
let arView = ARView(frame: .zero)
return arView
}
func updateUIView(_ uiView: ARView, context: Context) {}
}
struct ModelPickerView: View {
var models: [String]
var body: some View {
ScrollView(.horizontal, showsIndicators: false) {
HStack(spacing: 20) {
ForEach(0 ..<
self.models.count) { index in
Button(action: {
print("DEBUG: selected model with name: \(self.models[index])")
}) {
Image(uiImage: UIImage(named: self.models[index])!)
.resizable()
.frame(height: 60)
.aspectRatio(1/1,contentMode: .fit)
.background(Color.white)
.cornerRadius(12)
}
.buttonStyle (PlainButtonStyle())
}
}
}
.padding(15)
.background(Color.black.opacity(0.5))
}
struct PlacementButtonsView: View {
var body: some View {
HStack {
//Cancel Button
Button(action: {
print("DEBUG: model placement canceled.")
}) {
Image(systemName: "xmark")
.frame(width: 60, height: 60)
.font(.title)
.background(Color.white.opacity(0.75))
.cornerRadius(30)
.padding(20)
}
//Confirm Button
Button(action: {
print("DEBUG: model placement confirmed.")
}) {
Image(systemName: "checkmark")
.frame(width: 60, height: 60)
.font(.title)
.background(Color.white.opacity(0.65))
.cornerRadius(30)
.padding(20)
}
}
}
}
#if DEBUG
struct ContentView_Previews : PreviewProvider {
static var previews: some View {
ContentView()
}
}
#endif
}
Check your braces. The PlacementButtonsView struct is actually nested within the ModelPickerView struct, and not globally available, hence why it is not available from your ContentView.
By the way, in Xcode, you can find this out by option clicking on the declaration of PlacementButtonsView:
ModelPickerView.PlacementButtonsView shows you what went wrong here; PlacementButtonsView is nested within ModelPickerView. This is why you seem to have a strange closing brace on the final line of your code sample - the same issue occurs with the preview, as it is also nested in ModelPickerView.
To make this issue more visible, and see similar issues like this in the future more easily, you can also have Xcode indent your code for you by selecting all (Cmd + A) and then pressing Control + I. You'll see the PlacementButtonsView struct indent, making it more clear that it is not globally available.
I'm building an app that shares quite a bit of SwiftUI code between its iOS and macOS targets. On iOS, onDisappear seems to work reliably on Views. However, on macOS, onDisappear doesn't get called if the View is inside a sheet or popover.
The following code illustrates the concept:
import SwiftUI
struct ContentView: View {
#State private var textShown = true
#State private var showSheet = false
#State private var showPopover = false
var body: some View {
VStack {
Button("Toggle text") {
self.textShown.toggle()
}
if textShown {
Text("Text").onDisappear {
print("Text disappearing")
}
}
Button("Toggle sheet") {
self.showSheet.toggle()
}.sheet(isPresented: $showSheet, onDismiss: {
print("On dismiss")
}) {
VStack {
Button("Close sheet") {
self.showSheet = false
}
}.onDisappear {
print("Sheet disappearing")
}
}
Button("Toggle popover") {
self.showPopover.toggle()
}.popover(isPresented: $showPopover) {
VStack {
Text("popover")
}.onDisappear {
print("Popover disappearing")
}
}
}
.frame(maxWidth: .infinity, maxHeight: .infinity)
}
}
Note that onDisappear works fine on the Text component at the beginning of the VStack but the other two onDisappear calls don't get executed on macOS.
One workaround I've found is to attach an ObservableObject to the View and use deinit to call cleanup code. However, this isn't a great solution for two reasons:
1) With the popover example, there's a significant delay between the dismissal of the popover and the deist call (although it works quickly on sheets)
2) I haven't had any crashes on macOS with this approach, but on iOS, deinit have been unreliable in SwiftUI doing anything but trivial code -- holding references to my data store, app state, etc. have had crashes.
Here's the basic approach I used for the deinit strategy:
class DeinitObject : ObservableObject {
deinit {
print("Deinit obj")
}
}
struct ViewWithObservableObject : View {
#ObservedObject private var deinitObj = DeinitObject()
var body: some View {
Text("Deinit view")
}
}
Also, I would have thought I could use the onDismiss parameter of the sheet call, but that doesn't get called either on macOS. And, it's not an available parameter of popover.
All of this is using Xcode 11.4.1 and macOS 10.15.3.
Any solutions for good workarounds?
This question already has answers here:
Are there maximum limits to VStack?
(4 answers)
Closed 1 year ago.
I'm finishing an app that needs user data entry fields. I modeled it with a small number of data elements to streamline the development. Today I attempted to add additional elements and was astounded to find that I could only add 10 views to a view. So I tried the simplest of designs (below). If I added 11 "things" to the view it immediately presented the error on the top item, whatever it was:
"Argument passed to call that takes no arguments"
Doesn't matter whether I call the outside container a ScrollView, VStack, List or Form. Same behavior. Doesn't matter whether the Text/TextField sub units are in a VStack or not.
So I went back to basics - just added ten Text views. No problem. Add an eleventh and it blows up. Here's one of the variants - but all I need to do was add 10 simple Text views to get it to break.
I must be missing something really basic here. I checked for a newer release of Xcodebut I have Version 11.2 beta 2 (11B44), the latest.
#State private var textField1: String = "Pass to the ListCell"
#State private var textField2: String = "2"
//more of these
var body: some View {
NavigationView {
VStack {
//extract the VStack and create a separate struct
ListCell(tfString: textField1)
VStack {
Text("Text Field")
TextField("Placeholder", text: $textField2)
.textFieldStyle(RoundedBorderTextFieldStyle())
.padding()
}
VStack {
Text("Text Field")
TextField("Placeholder", text: $textField3)
.textFieldStyle(RoundedBorderTextFieldStyle())
.padding()
}
//more of the above VStacks
Text("6")
Text("7")
Text("8")
Text("9")
Text("10")
//Spacer()
//Text("11")
}
}
}
Any guidance would be appreciated.
Use Group {...} https://developer.apple.com/documentation/swiftui/group
var body: some View {
NavigationView {
VStack {
//extract the VStack and create a separate struct
ListCell(tfString: textField1)
Group {
VStack {
Text("Text Field")
TextField("Placeholder", text: $textField2)
.textFieldStyle(RoundedBorderTextFieldStyle())
.padding()
}
VStack {
Text("Text Field")
TextField("Placeholder", text: $textField3)
.textFieldStyle(RoundedBorderTextFieldStyle())
.padding()
}
}
//more of the above VStacks
Group {
Text("6")
Text("7")
Text("8")
Text("9")
Text("10")
}
//Spacer()
//Text("11")
}
}
}
ViewBuilders in SwiftUI take between 0 and 10 elements into their initializer anything more than that and you have to start grouping them using Group, VStack, HStack, List, ForEach and so on.
The best approach is to start extracting a few elements that belong together into separate Views, for example:
struct FormCell: View {
#Binding var inputString: String
var body: some View {
VStack {
Text("Text Field")
TextField("Placeholder", text: $inputString)
.textFieldStyle(RoundedBorderTextFieldStyle())
.padding()
}
}
}
Next if you have a few of them, you can group them using ForEach and List or VStack.
Use Group as people suggest.
However, you can extend ViewBuilder to make builders for more than 10 views. I created an article that walk you through it at More than 10 views in SwiftUI extending ViewBuilder.
I have just changed from Xcode 11 Beta 2, to Beta 3, and although I had to also change the navigationButton to navigationLink, all is ok, expect for the .animation()
Has anyone else seen this issue? Have they changed something? I was working just fine in Beta 2.
Thanks !!
import SwiftUI
struct BackGround : View {
var body: some View {
ZStack{
Rectangle()
.fill(Color.gray)
.opacity(0.9)
.cornerRadius(15.0)
.shadow(radius: /*#START_MENU_TOKEN#*/10/*#END_MENU_TOKEN#*/)
.blur(radius: 5)
.padding(20)
.animation(.basic())
}
}
}
I found that if I wrapped the content of a view in a VStack, perhaps other Stacks would also work, the view will animate in the previewer
Heres a quick example of a view that if wrapped in a VStack in the PreviewProvider previews the button will animate. But if the VStack is removed it will no longer animate. Try it out!
struct AnimatedButton : View {
#State var isAnimating: Bool = false
var body: some View {
Button(action: {
self.isAnimating.toggle()
}) {
Text("asdf")
}.foregroundColor(Color.yellow)
.padding()
.background(Color(.Green))
.cornerRadius(20)
.animation(.spring())
.scaleEffect(isAnimating ? 2.0 : 1.0)
}
}
#if DEBUG
struct FunButton_Previews : PreviewProvider {
static var previews: some View {
VStack {
AnimatedButton()
}
}
}
#endif