Last Run on XCODE 14.2 / iOS 16.2 / Swift 5.7.2

Making a Dynamic Button Link to heading

If you have noticed, the play button on most media players changes to pause once the media starts playing and vice versa. This is a behavior, I also needed in one of my apps that I was building.

It’s a functionality pretty staright forward to achieive in SwiftUI.

Single Button Link to heading

Lets start with the basics by creating a simple button in SwiftUI. This View takes two closures, one for the Label of the button and the other for the action to perform once the button is tapped. For the label, in the example below we are creating a SF Symbols based Image view of play to signify the play button. On tapping, the function play() is called.

Button(action: { play() }) {
    Image(systemName: "play")
        .font(.title)
}
func play() {
    print("Playing...")
}

However, once the play button is tapped we now need a pause button to provide the ability stop the currently playing media. A simple approach would be to create another button and handle the pause functionality, while disabling the play button.

Since, only one button action makes sense at a given time, a better and cleaner solution would be to make the button dynamic and handle both scenarios.

Make the Single Button Dynamic Link to heading

The first thing we would need is to track the state of the media player, if it’s currently playing or not. This can be tracked using a boolean @State property that we will name isPlaying. Next, let’s also rename the function from play() to handlerPlayPause() so a single function can handle both play and pause state. This function will also update the state of the isPlaying property any time the Button is tapped.

The SwiftUI code with the functionality to handle both play/pause with a single Button is shown below.

@State var isPlaying = false
var body: some View {
    VStack {
        Button(action: { handlePlayPause() }) {
            Image(systemName: isPlaying ? "pause": "play")
                .font(.title)
        }
    }
    .padding()
}

func handlePlayPause() {
    isPlaying.toggle()
    if isPlaying {
        print("Playing ...")
    }
    if !isPlaying {
        print("Paused ...")
    }
}