Swift
UIButton
iOS Development
Image Handling
SwiftUI

How to change UIButton image in Swift

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

In UIKit, changing a UIButton image usually means calling setImage(_:for:) for a specific control state. The main thing to decide is whether you want a new image for .normal, .highlighted, .selected, or another state, because buttons can show different images depending on interaction state.

The basic API is simple, but confusion usually comes from mixing foreground images with background images, or from expecting tint changes to work when the image is not in template mode.

Set the Image for a Button State

swift
1import UIKit
2
3let button = UIButton(type: .system)
4button.setImage(UIImage(named: "play"), for: .normal)
5button.setImage(UIImage(named: "pause"), for: .selected)

This means:

  • when the button is in its normal state, show play
  • when button.isSelected becomes true, show pause

That state-specific behavior is one reason UIButton image changes feel more subtle than changing a plain UIImageView.

To trigger the change:

swift
button.isSelected = true

Change the Image After an Event

A common pattern is to swap the image inside an action method:

swift
1import UIKit
2
3final class ViewController: UIViewController {
4    let button = UIButton(type: .system)
5
6    override func viewDidLoad() {
7        super.viewDidLoad()
8        button.setImage(UIImage(named: "sun"), for: .normal)
9        button.addTarget(self, action: #selector(toggleIcon), for: .touchUpInside)
10    }
11
12    @objc private func toggleIcon() {
13        let nextImage = UIImage(named: "moon")
14        button.setImage(nextImage, for: .normal)
15    }
16}

This is the simplest answer when the button image should change at runtime because of user interaction.

Use Template Images for Tinting

If you want the image color to follow the button tint, set the image to template rendering mode:

swift
let image = UIImage(named: "star")?.withRenderingMode(.alwaysTemplate)
button.setImage(image, for: .normal)
button.tintColor = .systemYellow

Without template rendering, changing tintColor often has no visible effect because the image keeps its original pixel colors.

setImage Versus setBackgroundImage

These are different APIs:

  • 'setImage changes the foreground icon'
  • 'setBackgroundImage changes the stretched background graphic'

Example:

swift
button.setBackgroundImage(UIImage(named: "button-bg"), for: .normal)

Use the right one for the visual role you mean. Many "why did my image layout look wrong?" bugs come from confusing these two.

Modern Configuration API

On newer UIKit codebases, UIButton.Configuration is also common:

swift
1var config = UIButton.Configuration.filled()
2config.image = UIImage(systemName: "heart.fill")
3config.title = "Like"
4
5let button = UIButton(configuration: config)

If you later update the configuration image, do it through the configuration object rather than mixing older and newer styling approaches inconsistently.

Working with System Symbols

If you are using SF Symbols instead of PNG assets, the same button APIs still apply:

swift
button.setImage(UIImage(systemName: "trash"), for: .normal)

This is often the cleanest option for standard interface icons because it avoids asset-management overhead and works naturally with tinting.

It also makes state-based image swapping easier, because symbol names are lightweight and integrate well with modern UIKit configuration APIs.

Common Pitfalls

  • Changing the image for .normal and expecting the button to update while it is currently showing another state.
  • Confusing setImage with setBackgroundImage.
  • Expecting tint changes to work on an image that is not rendered as a template.
  • Using asset names incorrectly and silently getting nil images.
  • Mixing legacy UIButton styling and configuration-based styling in ways that override each other unexpectedly.

Summary

  • Use setImage(_:for:) to change a UIButton foreground image.
  • Assign images per control state such as .normal or .selected.
  • Use template rendering if the button tint should recolor the image.
  • Use setBackgroundImage only for background graphics, not icon swaps.
  • Make sure you are updating the image for the state the button is actually displaying.

Course illustration
Course illustration

All Rights Reserved.