Build a Count Down Timer App for Your Apple Watch

Step-by-step guild to build a Count Down Timer app in Xcode with SwiftUI

ยท

5 min read

One of my best professors once told us that he doesn't own any devices that he can't develop for! That really made a lot of sense to me and made me look at all my devices differently.

As a developer, why would I just surrender to the apps that other developers have built on the devices that I own? Wouldn't it make a lot more sense to customize my device to perfectly suit my needs? After all, this is what I do for a living, so why not do it for myself?

You might be thinking that this is very time-consuming and may be very difficult depending on the complexity of the apps I need. You're not wrong, but you'd also be surprised how simple a lot of the apps that you actually need are. If you actually pay attention to the features that you use on the apps that you most, I'm willing to bet that on average, you use maybe 10% of the features of that app; in some cases, you probably only use 1 or 2 features. You'll quickly realize that building what you need is much simpler than you think; at least for the most part.

So, I'm currently in the market for an Apple Watch, and I'd like to test out this theory. I have little experience in building iOS apps with Swift in Xcode and have never built a watchOS app. So let's walk through a simple timer app for the watch and see how simple it is.

Make you have the latest version of Xcode installed before you start.

Step 1. Launch Xcode and select "Create a new Xcode project".

Step 2. Next to Project Name, give your app a name. I will call mine "countDown". Leave all other default settings.

Step 3. Once Xcode opens up your project, open the ContentView file from the file tree on the left.

You'll notice that there's a basic Hello World app already built for you. You can launch the simulator to see what it would look like on an actual watch. Click the play button icon in the top toolbar to run it.

Step 4. Delete the Hello World block, and let's declare 3 state variables at the top. A boolean variable for the state of the timer that lets us know if the timer is running, an integer variable for how much time to count down, and another boolean variable to let us know if the timer is playing or paused.

@State var countDownTimer = 5
@State var timerRunning = true
@State var isPlaying = false

Step 5. With one simple line, we can create the timer itself:

let timer = Timer.publish(every: 1, on: .main, in: .common).autoconnect()

Step 6. Now let's create the UI controls. Inside the body, let's create a parent VStack to vertically stack all our UI components. We want a TextView on top to display the time and below it, we want a + and a - button that side by side to increment and decrement the time. These 2 buttons will need to be in an HStack within the VStack. Below that HStack we want another one to hold to more buttons; a play/pause button and a stop button.

VStack(){
 Text("\(countDownTimer)")

 HStack(){
   Button {
      print("Increment")
   } label: {
      Image(systemName: "plus")
   }
   Button {
      print("Decrement")
   } label: {
      Image(systemName: "minus")
   }

  HStack(){
    Button {
      print("Start CountDown")
     } label: {
    Image(systemName: "play")
     }
    Button {
      print("Stop CountDown")
    } label: {
    Image(systemName: "stop")
    }
  }

}

You'll also notice that we added some icons to label the buttons accordingly.

Step 7. Now let's add some functionality to our buttons. For our TextView, we want to receive a signal from our timer emitter every 1 second and when we do, we will decrement our TextView by 1. However, we only want to do this until our timer reaches zero, then we want to turn off our timer.

Text("\(countDownTimer)")
  .onReceive(timer) { _ in
   if countDownTimer > 0 && timerRunning {
    countDownTimer -= 1
   } else {
    timerRunning = false
   }
 }

Step 8. Next let's make our increment and decrement buttons work. This is as simple as adding or subtracting 1 to our countDownTimer variable.

Button {
      print("Increment")
      countDownTimer = countDownTimer + 1
   } label: {
      Image(systemName: "plus")
   }
   Button {
      print("Decrement")
      countDownTimer = countDownTimer - 1
   } label: {
      Image(systemName: "minus")
   }

Step 9. Next let's handle our play/pause button and our stop button. We want to use the same button to play and pause. That means we need to toggle its function and label icon every time it's clicked. The stop button will send the timer to zero and timerRunning to false

Button {
      print("Start CountDown")
      if countDownTimer > 0 {
         timerRunning = true
         isPlaying = true
      } else {
         isPlaying = false
      }
     } label: {
      if (isPlaying){
          Image(systemName: "pause")
      } else {
          Image(systemName: "pause")
     }
    Button {
      print("Stop CountDown")
      timerRunning = false
      countDownTimer = 0
    } label: {
      Image(systemName: "stop")
    }

Step 10. Finally let's add some font style, some padding, and some colors to our icons. Here's what the final body should look like.

VStack(){
 Text("\(countDownTimer)")
    .font(.title)
    .fontWeight(.semibold)
    .padding()

 HStack(){
   Button {
      print("Increment")
      countDownTimer = countDownTimer + 1
   } label: {
      Image(systemName: "plus").font(system(size: 24))
   }
   Button {
      print("Decrement")
      countDownTimer = countDownTimer - 1
   } label: {
      Image(systemName: "minus").font(system(size: 24))
   }
}

  HStack(){
    Button {
      print("Start CountDown")
      if countDownTimer > 0 {
         timerRunning = true
         isPlaying = true
      } else {
         isPlaying = false
      }
     } label: {
      if (isPlaying){
          Image(systemName: "pause").foregroundColor(Color.orange)
      } else {
          Image(systemName: "play").foregroundColor(Color.green)
     }
    Button {
      print("Stop CountDown")
      timerRunning = false
      countDownTimer = 0
    } label: {
      Image(systemName: "stop").foregroundColor(Color.red)
    }
  }

}

Done

And there you have! You made your own countdown app for your own watch! ๐Ÿ‘๐Ÿฝ

ย