swiftuikituibutton

How to have UIButton image using UIButton.Configuration adapt and resize dynamically to the button size


I would like to use UIButton.Configuration to create and configure UIKit buttons in the app.

I cannot have the image in the button resizing accordingly to the size of the button itself leading to an image that expands outside of the button bounds.

Before configuration I was using .scaleAspectFit on the button imageView contentMode property.

import UIKit

class ViewController: UIViewController {

    let button1 = {
        let filterImageUrl = Bundle.main.url(forResource: "filter@2x", withExtension: "png")!
        let filterImage = UIImage(contentsOfFile: filterImageUrl.absoluteURL.path)

        var configuration = UIButton.Configuration.filled()
        configuration.image = filterImage
        configuration.imagePadding = 5
        configuration.cornerStyle = .medium
        configuration.baseBackgroundColor = .darkGray
        configuration.contentInsets = NSDirectionalEdgeInsets(top: 5, leading: 5, bottom: 5, trailing: 5)


        let button = UIButton(configuration: configuration)
        button.imageView?.contentMode = .scaleAspectFit
        button.translatesAutoresizingMaskIntoConstraints = false

        return button
    }()

    let button2 = {
        var configuration = UIButton.Configuration.filled()
        configuration.image = UIImage(systemName: "line.3.horizontal.decrease.circle")
        configuration.imagePadding = 5
        configuration.cornerStyle = .medium
        configuration.baseBackgroundColor = .darkGray

        let button = UIButton(configuration: configuration)
        button.setPreferredSymbolConfiguration(UIImage.SymbolConfiguration(scale: UIImage.SymbolScale.small), forImageIn: .normal)
        button.translatesAutoresizingMaskIntoConstraints = false

        return button
    }()

    override func viewDidLoad() {
        super.viewDidLoad()

        self.view.addSubview(button1)
        self.view.addSubview(button2)

        let constraint = [
            button1.centerXAnchor.constraint(equalTo: self.view.centerXAnchor),
            button1.centerYAnchor.constraint(equalTo: self.view.centerYAnchor),
            button1.widthAnchor.constraint(equalToConstant: 30),
            button1.heightAnchor.constraint(equalToConstant: 30),
            button2.topAnchor.constraint(equalTo: button1.bottomAnchor, constant: 10),
            button2.centerXAnchor.constraint(equalTo: self.view.centerXAnchor),
            button2.widthAnchor.constraint(equalToConstant: 20),
            button2.heightAnchor.constraint(equalToConstant: 20)
        ]
        NSLayoutConstraint.activate(constraint)
    }
}

The result is


Images in the buttons expands outside them

I tried to play with constraints, including imageView constraints against enclosing UIButton.

Also explored UIImage.Configuration

I also expects contentInsets configuration to force the image to resize inside the button


Solution

  • You are absolutely right that the image is not resized to fit the button; it's the other way around. Let the image, plus the configuration's contentInsets, size the button for you. Here's an example (from viewDidLoad) based loosely on your code:

    let button = {
        var configuration = UIButton.Configuration.filled()
        configuration.image = UIImage(systemName: "line.3.horizontal.decrease.circle")!
            .applyingSymbolConfiguration(.init(pointSize: 100))
        configuration.cornerStyle = .medium
        configuration.baseBackgroundColor = .darkGray
        configuration.contentInsets = .zero
        let button = UIButton(configuration: configuration)
        button.translatesAutoresizingMaskIntoConstraints = false
        return button
    }()
    
    self.view.addSubview(button)
    
    let constraints = [
        button.centerXAnchor.constraint(equalTo: self.view.centerXAnchor),
        button.centerYAnchor.constraint(equalTo: self.view.centerYAnchor),
    ]
    
    NSLayoutConstraint.activate(constraints)
    

    To vary the amount of "border" (padding? margin?), change the contentInsets value.