Skip to content

UIButton and Its Properties and Methods

UIButton is a fundamental UIKit control used to create interactive buttons in iOS apps. It is a subclass of UIControl and supports various configurations for appearance, behavior, and user interactions. This document covers the key properties and methods of UIButton, along with specific sections on configuration, applying roles, adding shadows, and attaching a UIMenu.

Overview of UIButton

A UIButton represents a tappable control that triggers actions when interacted with (e.g., tapped, pressed). It supports customizable text, images, backgrounds, and states (e.g., normal, highlighted, disabled). Buttons are versatile and can be styled to fit various design requirements.

Creating a UIButton

You can create a UIButton programmatically or via Interface Builder (storyboards/xibs).

Programmatic Example:

swift
import UIKit

let button = UIButton(type: .system)
button.setTitle("Tap Me", for: .normal)
button.addTarget(self, action: #selector(buttonTapped), for: .touchUpInside)
view.addSubview(button)

Key Properties of UIButton

Below are the most commonly used properties of UIButton:

PropertyTypeDescription
titleLabelUILabel?The label used for the button’s title (read-only, but configurable).
imageViewUIImageView?The image view used for the button’s image (read-only, but configurable).
configurationUIButton.ConfigurationDefines the button’s appearance and behavior (iOS 15+).
tintColorUIColorThe tint color applied to the button’s content (e.g., title, image).
isEnabledBoolWhether the button is enabled (affects appearance and interaction).
isHighlightedBoolWhether the button is highlighted (e.g., during touch).
isSelectedBoolWhether the button is selected (for toggle-style buttons).
contentEdgeInsetsUIEdgeInsetsPadding around the button’s content (title and image).
titleEdgeInsetsUIEdgeInsetsPadding for the title relative to the button’s bounds.
imageEdgeInsetsUIEdgeInsetsPadding for the image relative to the button’s bounds.
backgroundColorUIColor?The button’s background color (inherited from UIView).
layerCALayerThe button’s layer for advanced styling (e.g., shadows, borders).

Example: Configuring Properties:

swift
let button = UIButton(type: .system)
button.setTitle("Submit", for: .normal)
button.setImage(UIImage(systemName: "star.fill"), for: .normal)
button.tintColor = .systemBlue
button.contentEdgeInsets = UIEdgeInsets(top: 10, left: 20, bottom: 10, right: 20)
button.backgroundColor = .systemGray6

Key Methods of UIButton

UIButton inherits methods from UIControl and UIView, but also provides button-specific methods:

MethodDescription
setTitle(_:for:)Sets the title for a specific control state (e.g., .normal, .highlighted).
setImage(_:for:)Sets the image for a specific control state.
setBackgroundImage(_:for:)Sets the background image for a specific control state.
addTarget(_:action:for:)Associates an action with a control event (e.g., .touchUpInside).
setAttributedTitle(_:for:)Sets an attributed string as the title for a specific state.
title(for:)Returns the title for a specific state.
image(for:)Returns the image for a specific state.
sizeToFit()Resizes the button to fit its content (title and image).

Example: Adding an Action:

swift
button.addTarget(self, action: #selector(buttonTapped), for: .touchUpInside)

@objc func buttonTapped() {
    print("Button tapped!")
}

UIButton Configuration (iOS 15+)

Introduced in iOS 15, UIButton.Configuration provides a modern, declarative way to configure buttons, replacing older button types (e.g., .system, .custom). It simplifies styling and supports dynamic updates.

Common Configurations

  • .plain(): Minimal styling, similar to .system.
  • .tinted(): Applies a tinted background.
  • .filled(): A filled button with a solid background.
  • .bordered(): A button with a border.
  • .borderless(): A button without a border.

Example: Using Configuration:

swift
var config = UIButton.Configuration.filled()
config.title = "Confirm"
config.image = UIImage(systemName: "checkmark.circle")
config.imagePlacement = .leading
config.imagePadding = 8
config.baseForegroundColor = .white
config.baseBackgroundColor = .systemGreen
config.contentInsets = NSDirectionalEdgeInsets(top: 10, leading: 20, bottom: 10, trailing: 20)

let button = UIButton(configuration: config, primaryAction: UIAction { _ in
    print("Button tapped!")
})
view.addSubview(button)

Notes:

  • Use primaryAction to handle taps directly in the configuration.
  • imagePlacement and imagePadding control the layout of the image relative to the title.
  • Update the configuration dynamically with button.configuration = newConfig.

Applying Role to a UIButton

The role property (iOS 15+) defines the semantic role of a button, affecting its appearance and accessibility. Roles help convey the button’s purpose (e.g., primary action, destructive action).

Available Roles

  • .normal: Default appearance (no special styling).
  • .primary: Emphasized styling (e.g., filled background).
  • .cancel: Styling for cancel actions.
  • .destructive: Styling for actions that delete or remove (e.g., red tint).

Example: Applying a Role:

swift
var config = UIButton.Configuration.filled()
config.title = "Delete"
config.role = .destructive // Red styling for destructive action
let button = UIButton(configuration: config, primaryAction: UIAction { _ in
    print("Delete button tapped!")
})
view.addSubview(button)

Notes:

  • Roles automatically adjust the button’s appearance (e.g., colors) based on the configuration.
  • Combine with accessibility traits for better user experience (e.g., button.accessibilityTraits = .button).

Applying Shadow to a UIButton

You can add a shadow to a UIButton using its layer properties. Unlike UILabel, UIButton does not have shadowColor or shadowOffset properties for text, so shadows are applied to the entire button.

Steps:

  1. Set layer.shadowColor, layer.shadowOffset, layer.shadowOpacity, and layer.shadowRadius.
  2. Ensure layer.masksToBounds = false to allow the shadow to appear outside the button’s bounds.
  3. Optionally, set a cornerRadius for rounded buttons.

Example: Adding a Shadow:

swift
let button = UIButton(type: .system)
button.setTitle("Shadowed Button", for: .normal)
button.backgroundColor = .systemBlue
button.layer.cornerRadius = 8
button.layer.shadowColor = UIColor.black.cgColor
button.layer.shadowOffset = CGSize(width: 2, height: 2)
button.layer.shadowOpacity = 0.5
button.layer.shadowRadius = 4
button.layer.masksToBounds = false
view.addSubview(button)

Notes:

  • Shadows can impact performance in scrollable views; test on target devices.
  • Use layer.cornerRadius for rounded buttons to complement the shadow.
  • Adjust shadowOpacity (0.0 to 1.0) to control shadow intensity.

Attaching a UIMenu to a UIButton

A UIMenu can be attached to a UIButton to display a context menu when the button is long-pressed (iOS 13+). This is useful for providing additional actions related to the button.

Steps:

  1. Create a UIMenu with UIAction items.
  2. Assign the menu to the button’s menu property.
  3. Enable the context menu with showsMenuAsPrimaryAction = true for long-press or tap behavior.

Example: Adding a UIMenu:

swift
let button = UIButton(type: .system)
button.setTitle("Options", for: .normal)

// Create menu actions
let action1 = UIAction(title: "Copy", image: UIImage(systemName: "doc.on.doc")) { _ in
    print("Copy selected")
}
let action2 = UIAction(title: "Share", image: UIImage(systemName: "square.and.arrow.up")) { _ in
    print("Share selected")
}
let menu = UIMenu(title: "Options", children: [action1, action2])

// Assign menu to button
button.menu = menu
button.showsMenuAsPrimaryAction = true // Show menu on tap or long-press
view.addSubview(button)

Notes:

  • Use UIAction for simple menu items or UIMenu for nested menus.
  • Set showsMenuAsPrimaryAction = false to require a long-press to show the menu.
  • Ensure the button’s size is large enough for touch interactions (minimum 44x44 points).

Best Practices

  • Use Configurations (iOS 15+): Prefer UIButton.Configuration for modern, consistent styling.
  • Support Accessibility: Set accessibilityLabel and accessibilityTraits for VoiceOver support.
    swift
    button.accessibilityLabel = "Submit form"
    button.accessibilityTraits = .button
  • Handle States: Configure appearance for .normal, .highlighted, .disabled, and .selected states.
  • Use Auto Layout: Set translatesAutoresizingMaskIntoConstraints = false and use constraints (e.g., SnapKit) for positioning.
  • Test Interactions: Verify button behavior on different devices and in different states.
  • Optimize Performance: Minimize shadow usage in scrollable views and test with Instruments.

Troubleshooting

  • Button Not Responding: Ensure isEnabled = true and addTarget is correctly set for .touchUpInside.
  • Menu Not Showing: Verify menu is set and showsMenuAsPrimaryAction is configured.
  • Shadow Not Visible: Check that layer.masksToBounds = false and shadowOpacity > 0.
  • Text or Image Misaligned: Adjust contentEdgeInsets, titleEdgeInsets, or imageEdgeInsets.

Example: Complete UIButton Setup

swift
import UIKit
import SnapKit

class ViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()
        
        // Create button with configuration
        var config = UIButton.Configuration.filled()
        config.title = "Action"
        config.image = UIImage(systemName: "star.fill")
        config.imagePlacement = .leading
        config.imagePadding = 8
        config.baseBackgroundColor = .systemBlue
        config.role = .primary
        
        let button = UIButton(configuration: config, primaryAction: UIAction { _ in
            print("Button tapped!")
        })
        
        // Add shadow
        button.layer.shadowColor = UIColor.black.cgColor
        button.layer.shadowOffset = CGSize(width: 2, height: 2)
        button.layer.shadowOpacity = 0.5
        button.layer.shadowRadius = 4
        button.layer.masksToBounds = false
        
        // Add context menu
        let copyAction = UIAction(title: "Copy", image: UIImage(systemName: "doc.on.doc")) { _ in
            print("Copy selected")
        }
        let shareAction = UIAction(title: "Share", image: UIImage(systemName: "square.and.arrow.up")) { _ in
            print("Share selected")
        }
        button.menu = UIMenu(title: "Options", children: [copyAction, shareAction])
        button.showsMenuAsPrimaryAction = true
        
        view.addSubview(button)
        
        // Auto Layout with SnapKit
        button.snp.makeConstraints { make in
            make.center.equalToSuperview()
            make.width.equalTo(200)
            make.height.equalTo(50)
        }
    }
}

Resources

Released under the MIT License.