Home > Software engineering >  How to write a button function in swift 5.5, Xcode 13
How to write a button function in swift 5.5, Xcode 13

Time:03-10

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 Views. 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)
    }
}
  • Related