Your first app – Button Animation

In this code-along, we will create a simple button animation using SwiftUI. The button will switch between a gray circle and a green checkmark when tapped, with a smooth animation.

By the end, you’ll have a functional button like this:

  • When tapped, the button toggles between a gray circle and a green checkmark.
  • The transition is animated using SwiftUI’s withAnimation and symbolEffect.

Let’s get started!

Step 1: Set up your project

  1. Open Xcode: Launch Xcode and select Create a new Xcode project.
  2. Choose Template: Select App under the iOS tab and click Next.
  3. Name Your Project: Enter a name for your project, like ButtonAnimation. Choose SwiftUI for the interface and Swift for the language. Click Next, and then save your project.

When you open your project, you’ll see the following default code in ContentView.swift:

Swift
import SwiftUI

struct ContentView: View {
    var body: some View {
        VStack {
            Image(systemName: "globe")
                .imageScale(.large)
                .foregroundStyle(.tint)
            Text("Hello, world!")
        }
        .padding()
    }
}

#Preview {
    ContentView()
}

Let’s break down this code:

  • import SwiftUI: This line imports the SwiftUI framework, which provides the tools for building user interfaces.
  • struct ContentView: View { }: Defines a view called “ContentView” that conforms to the View protocol. In SwiftUI, all on-screen elements must conform to this protocol.
  • var body: some View { }: The body property describes the content of the view. It must return a value that conforms to the View protocol. The some keyword tells Swift that the exact type of view returned will be inferred.
  • VStack: A vertical stack layout container that arranges its child views vertically, one on top of the other.
  • Image(systemName: ): Displays a system icon (the globe).
  • Text: Displays a text string, here “Hello, world!”.
  • imageScale(.large)foregroundStyle(.tint): Modifiers that change the appearance of the Image view.
  • padding(): Adds space around the content of the VStack.
  • #Preview: Provides a live preview of the view in Xcode’s canvas, allowing you to see the UI changes in real-time.

This code demonstrates the basic structure of a SwiftUI view, including the use of a layout container (VStack), system images, text, and modifiers. It also showcases the live preview feature, which is essential for rapid prototyping and development in SwiftUI.

We’ll replace the default layout with our custom slider app. To begin, remove the following code from within the body property:

Swift
VStack {
	Image(systemName: "globe")
		.imageScale(.large)
		.foregroundStyle(.tint)
	Text("Hello, world!")
}
.padding()

For the label, we would like to use a checkmark with a circle around. That is a great opportunity to explore the so called SF Symbols.

Step 2: Exploring SF Symbols

SF Symbols provides thousands of consistent, highly configurable symbols that integrate seamlessly with the San Francisco system font, automatically aligning with text in all weights and sizes. You can read more about SF Symbols on Apple’s developer page:
SF Symbols. You can also download the SF Symbols app here: Download SF Symbols 6 App This app is great to explore all the different names for the SF symbols and to search for SF Symbols.

You can use SF Symbols very easily by using Image(systemName: ). With Image() you can create image views using a specific image you can add to your app or – if you want to use one of the pre-defined SF Symbols, you have to add systemName:. The systemName for a checkmark with a circle around is checkmark.circle. To change the size of an image you have to first apply the modifier resizable() and then add a frame with the desired height by using .frame(width: 50, height: 50):

Swift
Image(systemName: "checkmark.circle")
    .resizable()
    .frame(width: 50, height: 50)
    .foregroundStyle(.green)

This is the image we want to show when the image has been clicked. Otherwise it should show a gray circle. Instead of creating another image, there is a much better way to include everything in the image we just created by tracking whether the button is “pressed” or not. For that, we will create a so called @Statevariable.

Step 3: Create an @Statevariable

@Statetriggers that this variable is being monitored and if the value changes, the view will be updated.

Declare this state variable at the top of the struct – just before var body: some View {:

Swift
@State private var isPressed = false

How @State works?

  • @State makes the variable dynamic—whenever isPressed changes, SwiftUI will automatically update the UI.
  • We initialize it with false, meaning the button will start as an unpressed circle.

Step 4: Updating the Image

Next, we’ll update our Image view. The image will dynamically change based on whether isPressed is true or false.

Change the above created Imageto the following:

Swift
Image(systemName: isPressed ? "checkmark.circle" : "circle")

The systemName parameter dynamically selects the appropriate symbol based on the value of isPressed:

  • If isPressed is true, it shows "checkmark.circle".
  • If isPressed is false, it shows "circle".

This notation inside the Image is called “ternary conditional operator” and always looks like this:

Swift
condition ? valueIfTrue : valueIfFalse

which means: If the condition is true, the value valueIfTrue will be used, if the condition is false, then the value valueIfFalsewill be used. It is quite a nice concise syntax if the valueIfTrue and valueIfFalseare not extensively long.

Therefore

Swift
Image(systemName: isPressed ? "checkmark.circle" : "circle")

means, that the image will show the checkmark image if isPressedis true and just an empty circle otherwise.

To visually distinguish between the pressed and unpressed states, we’ll change the color of the symbol updating the .foregroundStyle() modifier:

Swift
.foregroundStyle(isPressed ? .green : .gray)

i.e.

  • When isPressed is true, the image turns green.
  • When isPressed is false, the image is gray.

Step 5: Add a smooth transition with contentTransition

We want the symbol to animate smoothly when switching between the circle and checkmark. To do this, we use the .contentTransition() modifier with a symbolEffect.

Swift
.contentTransition(.symbolEffect)

This adds an animation effect to the change of the symbol, making the transition visually smooth.

Step 6: Detect user taps with onTapGesture

To toggle the button when it’s tapped, we add the onTapGesture modifier. Inside it, we toggle the value of isPressedusing withAnimation to make the change animated:

Swift
.onTapGesture {
    withAnimation {
        isPressed.toggle()
    }
}

When the button is tapped, isPressed.toggle() reverses its value. The toggle method flips a boolean between true and false. Enclosing this within withAnimation ensures that the visual change occurs smoothly.

Step 8: Test your app

Now that your app layout is polished, it’s time to see it in action!

  1. Inspect the preview in the right-hand side panel of Xcode. If the preview is not visible, click the Resume button in the canvas toolbar.
  2. Run your app by selecting a simulator or a physical device at the top of Xcode and pressing the Play button (the right-pointing triangle).
  3. Tap the button to see the circle transition to a green checkmark and back!

Congratulations!

Congrats! You’ve created your first fully functional app! This simple yet powerful app is a great example of how small steps in SwiftUI can yield quick results.

What you have learned

In this code-along, you’ve learned:

  • How to declare and use an @State variable to dynamically track the button’s state.
  • How to use SF Symbols with Image(systemName:) to create icons.
  • How to resize and style images using .resizable().frame(), and .foregroundStyle().
  • How to create interactive buttons using onTapGesture and toggle the state.
  • How to animate changes with withAnimation and contentTransition(.symbolEffect).

This small project shows how simple changes in SwiftUI can yield dynamic and interactive effects. Keep experimenting with more animations and styles to enhance your UI design!

Keep learning, keep building, and let your curiosity guide you. Happy coding! ✨

“Stay hungry. Stay foolish.” — Steve Jobs


Download the full project on GitHub: https://github.com/swiftandcurious/ButtonAnimation.git

Watch the full code-along