let sometext: LocalizedStringKey = "sometext"
var body: some View {
Text(sometext + " some more text") // Error: Binary operator '+' cannot be applied to operands of type 'LocalizedStringKey' and 'String'
}
Why does this not work and how can I fix it?
I also found that, but I as a beginner do not really understand the answer
https://www.reddit.com/r/swift/comments/d50afb/localizedstringkey_to_string/
This is how you add text together in swiftUI.
var body: some View {
Text(sometext) + Text("some more text")
}
Related
I am trying to use an optional #State variable with a TextField. This is my code:
struct StorageView: View {
#State private var storedValue: String?
var body: some View {
VStack {
TextField("Type a value", text: $storedValue)
}
}
}
When I use this code, I get the following error:
Cannot convert value of type 'Binding<String?>' to expected argument type 'Binding<String>'
I have tried the following code for both the values to be optional, but nothing seems to work:
TextField("Type a value", text: $storedValue ?? "")
TextField("Type a value", text: Binding($storedValue)!)
How would I go about using an optional #State variable with a binding? Any help with this is appreciated.
How would I go about using an optional #State variable with a binding? Any help with this is appreciated.
It looks like you are using an optional state variable with a binding. You get an error because TextField's initializer expects a Binding<String> rather than a Binding<String?>. I guess you could solve the problem by adding another initializer that accepts Binding<String?>, or maybe making an adapter that converts between Binding<String?> and Binding<String>, but a better option might be to have a good think about why you need your state variable to be optional in the first place. After all this string something that will be displayed in your UI -- what do you expect your TextField to display if storedValue is nil?
This question already has answers here:
Swift closure syntax using { ... in }
(2 answers)
Closed 1 year ago.
I've seen the word "in" multiple times in SwiftUI, but don't quite understand what it means. Because the word is so short and common, I'm having a hard time searching for its meaning and usage.
Most recently, I've seen it in the onChange method for example:
struct ContentView: View {
#State private var name = ""
var body: some View {
TextField("Enter your name:", text: $name)
.textFieldStyle(RoundedBorderTextFieldStyle())
.onChange(of: name) { newValue in
print("Name changed to \(name)!")
}
}
As like in your code example using in afther newValue let`s Swift and you know the return value of process is going happen on newValue so it is more like a symbol or flag called: "token" to you and to CPU that work is going happen on newValue because you put it before in, for example you gave name to onChange modifier with using newValue in, you will get updated value for name if get any new update, also note you can use $0 instead of newValue in and works same.
.onChange(of: name) { newValue in
return print("Name changed to \(name)!")
}
Or:
.onChange(of: name) {
print("Name changed to \($0)!")
}
Both are the same it depends how you like it.
Another example for better understanding:
let arrayOfInt: [Int] = [1, 2, 3]
let arrayOfString: [String] = arrayOfInt.map({ value in return value.description })
let arrayOfString: [String] = arrayOfInt.map({ $0.description })
For example we have an arrayOfInt and we want create a String array of it, for this work we can use map, and again like last example we used in in 2 way. in the first one as: value in and in the second on as $0. I recommend you work and learn more about closure in Swift/SwiftUI they are very important, without knowing them well, we cannot have good understanding of codes in iOS.
Also do not forget to attention to word of return right after in you can type and use or not use it, Swift is Smart enough to understand because of inference, but if you use it, it make your code much more easy and simple to read and better in syntax of code.
I have implemented Localisation in my SwiftUI app. Everything works fine but I'm having issues with localising #State var. Localisation is not working and I'm getting only the keys printed out. Any idea how to fix this issue?
The value of type is already in my Localizable.strings
#State var type: String
var body: some View {
VStack {
Text(self.type) // not working
Text("test") // working
}
}
You can take convert the string into a NSLocalizedString
Text(NSLocalizedString(type, comment: ""))
or change the type of type into a LocalizedStringKey
#State var type: LocalizedStringKey
When a string literal is passed to Text its type needs to be inferred (Since it isn't explicitly stated). Literal text is probably a fixed part of your UI, so it is interpreted as a LocalizedStringKey.
When you pass the property self.type, it has an explicit type - String, so the Text(_ verbatim:) initialiser is used resulting in non-localised text.
If you want that property to be localised you can use the LocalizedStringKey(_ string: String) initialiser:
Text(LocalizedStringKey(self.type))
I'm trying to understand how to change #State variables in #ViewBuilder closures. The following is just a simple example:
struct ContentView: View {
#State var width = CGFloat(0)
var body: some View { //Error 1
GeometryReader { geometry in //Error 2
self.width = geometry.size.width
return Text("Hello world!")
}
}
}
I'm getting some errors:
Error 1:
Function declares an opaque return type, but has no return statements
in its body from which to infer an underlying type
But the return is redundant because there's only one line of code inside the View computed property.
Error 2:
Cannot convert return expression of type 'GeometryReader<_>' to return
type 'some View'
Since I explicitly write return Text("...") shouldn't the type be clear?
What's the problem here?
First, you can't make arbitrary swift statements in a functionBuilder. There is a specific syntax allowed. In SwiftUI's case, it's a ViewBuilder, which under the hood is composing your type. When you make consecutive statements in SwiftUI, you are actually relying on the compiler to compose a new type underneath according to the rules of that DSL.
2nd, SwiftUI is a recipe, it's not an event system. You don't change state variables in the body function, you set up how things should react when state variables change externally. If you want another view to react in some way to that width, you need to define that content with respect to the width of the component you want. Without knowing what your ultimate goal is here, it's hard to answer how to relate the content to each other.
EDIT:
I was asked to elaborate on what exactly is allowed. Each functionBuilder has a different allowable syntax which is defined in the functionBuilder itself. This has a good overview on function builders in Swift 5.1: https://www.swiftbysundell.com/posts/the-swift-51-features-that-power-swiftuis-api
As for what SwiftUI is specifically looking for, it's essentially looking for each statement to return an instance of View.
// works fine!
VStack {
Text("Does this")
Text("Work?")
}
// doesn't work!
VStack {
Text("Updating work status...")
self.workStatus = .ok // this doesn't return an instance of `View`!
}
// roundabout, but ok...
VStack {
Text("Being clever")
gimmeView()
}
// fine to execute arbitrary code now, as long as we return a `View`
private func gimmeView() -> some View {
self.workingStatus = .roundabout
return Text("Yes, but it does work.")
}
This is why you got the obtuse error you got:
Cannot convert return expression of type 'GeometryReader<_>' to return type 'some View'
The type system can't construct any View out of View and essentially Void when you execute:
self.width = geometry.size.width
When you do consecutive View statements, underneath, it's still being converted into a new type of View:
// the result of this is TupleView<Text, Text>
Text("left")
Text("right")
In SwiftUI, you can combine Text objects like so:
var body: some View {
Text("You can") + Text(" add lots of objects that wrap normally")
}
This gives the benefit of having multiple Text objects that act as one, meaning they are on the same line and wrap appropriately.
What I can't figure out is how to combine n number of Text objects, based on an array or really any way to increment.
I've tried ForEach like so,
var texts = ["You can", " add lots of objects that wrap normally"]
var body: some View {
ForEach(texts.identified(by: \.self)) {
Text($0)
}
}
But that looks like this
when I want it to look like this
Could anyone show me how this is done?
Use case: Styling part of a Text object and not the other parts. Like what is possible with NSMutableAttributedString
You seem to be describing something like this:
var body: some View {
let strings = ["manny ", "moe", " jack"]
var texts = strings.map{Text($0)}
texts[1] = texts[1].underline() // illustrating your use case
return texts[1...].reduce(texts[0], +)
}
However, I think it would be better to wait until attributed strings arrive.