49

I am able to set the image and text for button. But it is aligned horizontally. I want the image and text to be aligned vertically inside the button. i.e., text below the image

How to make these changes using storyboard?

What I want is this:

enter image description here

What I am getting now is this: enter image description here

iHarshil
  • 739
  • 10
  • 22
Ahalya Hegde
  • 1,571
  • 2
  • 18
  • 41

9 Answers9

48

If you are looking for output like this

Button Image with Text

1) Select button and go to Attribute Inspector in your storyboard to get this result of Button size 50*50

enter image description here

2) Now set Title Insets of Button

enter image description here

Sourabh Sharma
  • 8,222
  • 5
  • 68
  • 78
30

I've written an extension that do the works for you, Swift 4 compatible.

public extension UIButton {

    func alignTextBelow(spacing: CGFloat = 6.0) {
        if let image = self.imageView?.image {
            let imageSize: CGSize = image.size
            self.titleEdgeInsets = UIEdgeInsetsMake(spacing, -imageSize.width, -(imageSize.height), 0.0)
            let labelString = NSString(string: self.titleLabel!.text!)
            let titleSize = labelString.size(withAttributes: [NSAttributedStringKey.font: self.titleLabel!.font])
            self.imageEdgeInsets = UIEdgeInsetsMake(-(titleSize.height + spacing), 0.0, 0.0, -titleSize.width)
        }
    }

}

Where spacing is the distance between image and text.

Luca Davanzo
  • 21,000
  • 15
  • 120
  • 146
  • Yes it does. A little correction though: let imageSize = self.imageView!.frame.size – Borzh Jun 05 '18 at 00:44
  • titleEdgeInsets must be set to this: self.titleEdgeInsets = UIEdgeInsetsMake(imageSize.height + spacing, -imageSize.width, -(imageSize.height), 0.0) – Maryoomi1 Jun 24 '18 at 13:01
  • it's a nice solution – fAiSaL Jul 23 '18 at 05:39
  • Problem with this solution is if I change the text dynamically, the image moves left and right depending on the text. How do I keep image stable while accounting for maximum title size height? – Deepak Sharma Feb 11 '19 at 18:17
  • The other problem with this solution and I've tried similar ones to this is, it's breaking Layout Constraints and the console is going bonkers with all the broken constraints. – C0D3 Oct 02 '20 at 18:06
21

Yes you can do it from storyboard without writing any logic also.

1) Select button and go to Attribute Inspector in your storyboard.

2) Assign Image to the button. (Don't use background Image)

3) Set Title text to that button.

4) Now you need to set edge and Inset so first select image from edge and set Inset as you need and then select title from edge and set inset as per your need.

Hope this helps.

Jigar Tarsariya
  • 3,189
  • 3
  • 14
  • 38
9

You can easily and visually achieve the alignment using the Edge property of the Button from Property Window(Attribute Inspector) you can change the inset values of Title, and Image as per your need, see image below

enter image description here

Hope it helps.

Cheers.

iphonic
  • 12,615
  • 7
  • 60
  • 107
7

Swift 4.2 compatible code is here , you just need to call this function

  public extension UIButton
  {

    func alignTextUnderImage(spacing: CGFloat = 6.0)
    {
        if let image = self.imageView?.image
        {
            let imageSize: CGSize = image.size
            self.titleEdgeInsets = UIEdgeInsets(top: spacing, left: -imageSize.width, bottom: -(imageSize.height), right: 0.0)
            let labelString = NSString(string: self.titleLabel!.text!)
            let titleSize = labelString.size(withAttributes: [NSAttributedString.Key.font: self.titleLabel!.font])
            self.imageEdgeInsets = UIEdgeInsets(top: -(titleSize.height + spacing), left: 0.0, bottom: 0.0, right: -titleSize.width)
        }
    }
}
Shahzaib Maqbool
  • 1,479
  • 16
  • 25
1

a refined one

func alignTextUnderImage(spacing: CGFloat = 6.0) {
    guard let image = imageView?.image, let label = titleLabel,
      let string = label.text else { return }

      titleEdgeInsets = UIEdgeInsets(top: spacing, left: -image.size.width, bottom: -image.size.height, right: 0.0)
      let titleSize = string.size(withAttributes: [NSAttributedString.Key.font: label.font])
      imageEdgeInsets = UIEdgeInsets(top: -(titleSize.height + spacing), left: 0.0, bottom: 0.0, right: -titleSize.width)
  }

rbiard
  • 76
  • 4
0

Thank you @rbiard. Another workaround when you are developing a multilingual mobile app and when using UISemanticContentAttribute (right to left and left to right). This should work:

func alignTextBelow(spacing: CGFloat = 10.0) {
    guard
        let image = imageView?.image,
        let label = titleLabel,
        let string = label.text
    else { return }

    let titleSize = string.size(withAttributes: [NSAttributedString.Key.font: label.font])
    
    //when the selected language is English
    if L102Language.currentAppleLanguage() == "en" {      
        titleEdgeInsets = UIEdgeInsets(top: spacing, left: -image.size.width, bottom: -image.size.height, right: 0)
        imageEdgeInsets = UIEdgeInsets(top: -(titleSize.height + spacing), left: 0.0, bottom: 0.0, right: -titleSize.width)
    } else {
        //When selecting a right to left language. For example, Arabic            
        titleEdgeInsets = UIEdgeInsets(top: spacing, left: 0, bottom: -image.size.height, right: -image.size.width)
        imageEdgeInsets = UIEdgeInsets(top: -(titleSize.height + spacing), left: -titleSize.width, bottom: 0, right: 0)
    }
}
Community
  • 1
  • 1
Maryoomi1
  • 113
  • 1
  • 3
  • 16
0

Setting Attribute Inspector in storyboard

  1. Setup button size
  2. Setup image's top
  3. Setup title's top and left enter image description here
yycking
  • 1,017
  • 1
  • 9
  • 14
-1

You cannot change layout directly in UIButton, but you can try to use these properties on UIButton:

UIButton *button = ...
button.titleEdgeInsets = UIEdgeInsetsMake(....);
button.imageEdgeInsets = UIEdgeInsetsMake(....);

If it won't help I'd recommend to subclass from UIResponder and make your own component and do your own layout as you needed it.

Konstantin
  • 861
  • 4
  • 12