Kieran Paddock
Kieran Paddock

Reputation: 413

UIButton in Swift with two images

I'm trying to make a UIButton that has a UIImage on either side (left and right) of the button's title. Ideally, the images would be pinned to the left and right sides of the button, and the title would be centered, but I can live with the images being right next to the title label I suppose. I have been able to add one image, which appears right before the title, but how would I add a second?

Upvotes: 14

Views: 9190

Answers (4)

Pratik
Pratik

Reputation: 726

Swift 5, XCode 11.6

Please use the below code in your extension or in a custom UIButton class. I have used the below code in my custom class. The function will set left or right image respectively and align the text.

/// Sets a left and right image for a button
/// - Parameters:
///   - right: right image
///   - left: left image
func setImages(right: UIImage? = nil, left: UIImage? = nil) {
    if let leftImage = left, right == nil {
        setImage(leftImage, for: .normal)
        imageEdgeInsets = UIEdgeInsets(top: 5, left: (bounds.width - 35), bottom: 5, right: 5)
        titleEdgeInsets = UIEdgeInsets(top: 0, left: 10, bottom: 0, right: (imageView?.frame.width)!)
        contentHorizontalAlignment = .left
    }
    if let rightImage = right, left == nil {
        setImage(rightImage, for: .normal)
        imageEdgeInsets = UIEdgeInsets(top: 5, left: 5, bottom: 5, right: (bounds.width - 35))
        titleEdgeInsets = UIEdgeInsets(top: 0, left: (imageView?.frame.width)!, bottom: 0, right: 10)
        contentHorizontalAlignment = .right
    }

    if let rightImage = right, let leftImage = left {
        setImage(rightImage, for: .normal)
        imageEdgeInsets = UIEdgeInsets(top: 5, left: 5, bottom: 5, right: (bounds.width - 35))
        titleEdgeInsets = UIEdgeInsets(top: 0, left: (imageView?.frame.width)!, bottom: 0, right: 10)
        contentHorizontalAlignment = .left

        let leftImageView = UIImageView(frame: CGRect(x: bounds.maxX - 30,
                                                      y: (titleLabel?.bounds.midY)! - 5,
                                                      width: 20,
                                                      height: frame.height - 10))
        leftImageView.image?.withRenderingMode(.alwaysOriginal)
        leftImageView.image = leftImage
        leftImageView.contentMode = .scaleAspectFit
        leftImageView.layer.masksToBounds = true
       addSubview(leftImageView)
    }

}

Usage:

  1. vegaButton.setImage(right: myImage) // for right image
  2. vegaButton.setImage(left: myImage) // for left image
  3. vegaButton.setImage(right: myImage, left: myImage) // for both images.

Upvotes: 0

Zp1k_e
Zp1k_e

Reputation: 138

Add a UIImageView with an image to the button by addSubview and another to the button by setImage, it can be adjusted with titleEdgeInsets and imageEdgeInsets.

if you need a code sample – let me know.

Hope it helps!

Upvotes: 1

NoSixties
NoSixties

Reputation: 2533

I know this is an old question but since no code was provided and someone asked for it I figured I would share my solution for this.

What I did was create a new class which subclasses a UIButton. I made sure that you can see all the changes you do instantly in your interface builder as well. So you can just drag in a UIButton. Specify the class to your own class and it will allow you to set the images and see it being drawn instantly

Here is what I did to achieve this

import UIKit

@IBDesignable
class AddProfilePictureView: UIButton {

    @IBInspectable var leftHandImage: UIImage? {
        didSet {
            leftHandImage = leftHandImage?.withRenderingMode(.alwaysOriginal)
            setupImages()
        }
    }
    @IBInspectable var rightHandImage: UIImage? {
        didSet {
            rightHandImage = rightHandImage?.withRenderingMode(.alwaysTemplate)
            setupImages()
        }
    }

    func setupImages() {
        if let leftImage = leftHandImage {
            self.setImage(leftImage, for: .normal)
            self.imageView?.contentMode = .scaleAspectFill
            self.imageEdgeInsets = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: self.frame.width - (self.imageView?.frame.width)!)
        }

        if let rightImage = rightHandImage {
            let rightImageView = UIImageView(image: rightImage)
            rightImageView.tintColor = COLOR_BLUE

            let height = self.frame.height * 0.2
            let width = height
            let xPos = self.frame.width - width
            let yPos = (self.frame.height - height) / 2

            rightImageView.frame = CGRect(x: xPos, y: yPos, width: width, height: height)
            self.addSubview(rightImageView)
        }
    }
}

Upvotes: 16

user5034511
user5034511

Reputation:

I would break it into two buttons within a collection view- it's very flexible and can work great for something like this.

Upvotes: 0

Related Questions