So im trying to make the code neater by taking the code required to create a new button and chucking it into a function called makeButton.
Im very new to swift and Xcode, my thinking behind this is that in Java one would almost exclusively work with methods for greater abstraction so I should attempt to do the same here. This is the code I've written and I'm having a hard time understanding why im getting a compiler error; specifically: "type '()' cannot conform to 'View'." What am I doing wrong? It seems to me that this would totally work in Java. Here is my code:
[enter image description here][1]
import AVFoundation
struct ContentView: View {
let buttonText1 : String = "hello world"
let buttonText2 : String = "welcome to Swift!"
var body: some View {
VStack {
makeButton(text: buttonText1, bezel: 10);
makeButton(text: buttonText2, bezel: 10);
}
}
func makeButton(text: String, bezel: CGFloat){
Button{
let utterance = AVSpeechUtterance(string: text)
utterance.voice = AVSpeechSynthesisVoice(language: "en-gb")
let synthesizer = AVSpeechSynthesizer()
synthesizer.speak(utterance)
}label: {
Text(text)
.fontWeight(.bold)
.font(.system(.title, design: .rounded))
.font(.title)
}
.padding()
.foregroundColor(.yellow)
.background(Color.red)
.cornerRadius(bezel)
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
[1]: https://i.stack.imgur.com/xcuyN.png
CodePudding user response:
The error is occurring because in Swift, you are expected to explicitly annotate the return types of functions.
Your function signature should look like this:
func makeButton(text: String, bezel: CGFloat) -> some View {
You'll also notice that with your current code, there's a warning:
Result of call to 'cornerRadius(_:antialiased:)' is unused
This stems from the same issue -- without a return type, Swift thinks you're just creating a Button
and doing nothing with it. However, with the return type, you have what's called an "implicit return", meaning singular statement gets returned from the function automatically.
Finally, the Swift-ier way to do this, as opposed to functions, is by composing View
s. So, a refactor would look like this:
struct ContentView: View {
let buttonText1 : String = "hello world"
let buttonText2 : String = "welcome to Swift!"
var body: some View {
VStack {
MyButton(text: buttonText1, bezel: 10)
MyButton(text: buttonText2, bezel: 10)
}
}
}
struct MyButton : View {
var text : String
var bezel : CGFloat
var body: some View {
Button{
let utterance = AVSpeechUtterance(string: text)
utterance.voice = AVSpeechSynthesisVoice(language: "en-gb")
let synthesizer = AVSpeechSynthesizer()
synthesizer.speak(utterance)
}label: {
Text(text)
.fontWeight(.bold)
.font(.system(.title, design: .rounded))
.font(.title)
}
.padding()
.foregroundColor(.yellow)
.background(Color.red)
.cornerRadius(bezel)
}
}