Adding Space/Padding to a Uilabel

Adding space/padding to a UILabel

If you want to stick with UILabel, without subclassing it, Mundi has given you a clear solution.

If alternatively, you would be willing to avoid wrapping the UILabel with a UIView, you could use UITextView to enable the use of UIEdgeInsets (padding) or subclass UILabel to support UIEdgeInsets.

Using a UITextView would only need to provide the insets (Objective-C):

textView.textContainerInset = UIEdgeInsetsMake(10, 0, 10, 0);

Alternative, if you subclass UILabel, an example to this approach would be overriding the drawTextInRect method

(Objective-C)

- (void)drawTextInRect:(CGRect)uiLabelRect {
UIEdgeInsets myLabelInsets = {10, 0, 10, 0};
[super drawTextInRect:UIEdgeInsetsInsetRect(uiLabelRect, myLabelInsets)];
}

You could additionally provide your new subclassed UILabel with insets variables for TOP, LEFT, BOTTOM and RIGHT.

An example code could be:

In .h (Objective-C)

float topInset, leftInset,bottomInset, rightInset;

In .m (Objective-C)

- (void)drawTextInRect:(CGRect)uiLabelRect {
[super drawTextInRect:UIEdgeInsetsInsetRect(uiLabelRect, UIEdgeInsetsMake(topInset,leftInset,bottomInset,rightInset))];
}

From what I have seen, it seems you have to override the intrinsicContentSize of the UILabel when subclassing it.

So you should override intrinsicContentSize like:

- (CGSize) intrinsicContentSize {
CGSize intrinsicSuperViewContentSize = [super intrinsicContentSize] ;
intrinsicSuperViewContentSize.height += topInset + bottomInset ;
intrinsicSuperViewContentSize.width += leftInset + rightInset ;
return intrinsicSuperViewContentSize ;
}

And add the following method to edit your insets, instead of editing them individually:

- (void) setContentEdgeInsets:(UIEdgeInsets)edgeInsets {
topInset = edgeInsets.top;
leftInset = edgeInsets.left;
rightInset = edgeInsets.right;
bottomInset = edgeInsets.bottom;
[self invalidateIntrinsicContentSize] ;
}

It will update the size of your UILabel to match the edge insets and cover the multiline necessity you referred to.

After searching a bit I have found this Gist with an IPInsetLabel. If none of those solutions work you could try it out.

There was a similar question (duplicate) about this matter.

For a full list of available solutions, see this answer: UILabel text margin

UILabel border and padding

I solved the issue!

For those how are facing the same problem:

1- Make a class extending from UILabel:

UILabelPadding.swift:

class UILabelPadding: UILabel {

let padding = UIEdgeInsets(top: 2, left: 8, bottom: 2, right: 8)
override func drawText(in rect: CGRect) {
super.drawText(in: rect.inset(by: padding))
}

override var intrinsicContentSize : CGSize {
let superContentSize = super.intrinsicContentSize
let width = superContentSize.width + padding.left + padding.right
let heigth = superContentSize.height + padding.top + padding.bottom
return CGSize(width: width, height: heigth)
}



}

2- Set the type of your label to the UILabelPadding and make sure that the type is set also in the storyboard.

UILabel text margin

I solved this by subclassing UILabel and overriding drawTextInRect: like this:

- (void)drawTextInRect:(CGRect)rect {
UIEdgeInsets insets = {0, 5, 0, 5};
[super drawTextInRect:UIEdgeInsetsInsetRect(rect, insets)];
}

Swift 3.1:

override func drawText(in rect: CGRect) {
let insets = UIEdgeInsets.init(top: 0, left: 5, bottom: 0, right: 5)
super.drawText(in: UIEdgeInsetsInsetRect(rect, insets))
}

Swift 4.2.1:

override func drawText(in rect: CGRect) {
let insets = UIEdgeInsets(top: 0, left: 5, bottom: 0, right: 5)
super.drawText(in: rect.inset(by: insets))
}

As you might have gathered, this is an adaptation of tc.'s answer. It has two advantages over that one:

  1. there's no need to trigger it by sending a sizeToFit message
  2. it leaves the label frame alone - handy if your label has a background and you don't want that to shrink

Swift & UILabel : How to add padding and margin in Swift programmatically?

You can insert this UILabel into the container (any UIView) and set its position inside.

But the simplest trick is to use UIButton instead of UILabel. You can configure UIEdgeInsets for padding.

So that UIButton does not act as a button simply set button.isUserInteractionEnabled = false.

By default, text in the button are placed in the center, but its position is easy to change with contentHorizontalAlignment and contentVerticalAlignment

And as a bonus, you can add icons right near to the text. :)

UPD.

Could you give me a simple example? I tried that way but I didn't get the result I expected. – Punreach Rany

let buttonUsedAsLabel = UIButton()
// Your question was about padding
// It's it!
buttonUsedAsLabel.titleEdgeInsets = UIEdgeInsets(top: 5, left: 20, bottom: 5, right: 20)
// Make it not user interactable as UILabel is
buttonUsedAsLabel.isUserInteractionEnabled = false
// set any other properties
buttonUsedAsLabel.setTitleColor(.white, for: .normal)
buttonUsedAsLabel.contentVerticalAlignment = .top
buttonUsedAsLabel.contentHorizontalAlignment = .left
// Set title propeties AFTER it was created with text because it's nullable
// You can use attributed title also
// Never use any (button.titleLabel) before its creation
// for example: (button.titleLabel?.text = "zzz") do nothing here
buttonUsedAsLabel.setTitle("This is the text", for: .normal)
buttonUsedAsLabel.titleLabel?.font = .systemFont(ofSize: 20, weight: .medium)
buttonUsedAsLabel.titleLabel?.numberOfLines = 0
buttonUsedAsLabel.titleLabel?.lineBreakMode = .byWordWrapping
// and so on
// ...
// This is the triсk :)

Of course, you can do it with a storyboard if prefer.

Adding space/padding to a UILabel

If you want to stick with UILabel, without subclassing it, Mundi has given you a clear solution.

If alternatively, you would be willing to avoid wrapping the UILabel with a UIView, you could use UITextView to enable the use of UIEdgeInsets (padding) or subclass UILabel to support UIEdgeInsets.

Using a UITextView would only need to provide the insets (Objective-C):

textView.textContainerInset = UIEdgeInsetsMake(10, 0, 10, 0);

Alternative, if you subclass UILabel, an example to this approach would be overriding the drawTextInRect method

(Objective-C)

- (void)drawTextInRect:(CGRect)uiLabelRect {
UIEdgeInsets myLabelInsets = {10, 0, 10, 0};
[super drawTextInRect:UIEdgeInsetsInsetRect(uiLabelRect, myLabelInsets)];
}

You could additionally provide your new subclassed UILabel with insets variables for TOP, LEFT, BOTTOM and RIGHT.

An example code could be:

In .h (Objective-C)

float topInset, leftInset,bottomInset, rightInset;

In .m (Objective-C)

- (void)drawTextInRect:(CGRect)uiLabelRect {
[super drawTextInRect:UIEdgeInsetsInsetRect(uiLabelRect, UIEdgeInsetsMake(topInset,leftInset,bottomInset,rightInset))];
}

From what I have seen, it seems you have to override the intrinsicContentSize of the UILabel when subclassing it.

So you should override intrinsicContentSize like:

- (CGSize) intrinsicContentSize {
CGSize intrinsicSuperViewContentSize = [super intrinsicContentSize] ;
intrinsicSuperViewContentSize.height += topInset + bottomInset ;
intrinsicSuperViewContentSize.width += leftInset + rightInset ;
return intrinsicSuperViewContentSize ;
}

And add the following method to edit your insets, instead of editing them individually:

- (void) setContentEdgeInsets:(UIEdgeInsets)edgeInsets {
topInset = edgeInsets.top;
leftInset = edgeInsets.left;
rightInset = edgeInsets.right;
bottomInset = edgeInsets.bottom;
[self invalidateIntrinsicContentSize] ;
}

It will update the size of your UILabel to match the edge insets and cover the multiline necessity you referred to.

After searching a bit I have found this Gist with an IPInsetLabel. If none of those solutions work you could try it out.

There was a similar question (duplicate) about this matter.

For a full list of available solutions, see this answer: UILabel text margin

Adding space/padding to a UILabel

If you want to stick with UILabel, without subclassing it, Mundi has given you a clear solution.

If alternatively, you would be willing to avoid wrapping the UILabel with a UIView, you could use UITextView to enable the use of UIEdgeInsets (padding) or subclass UILabel to support UIEdgeInsets.

Using a UITextView would only need to provide the insets (Objective-C):

textView.textContainerInset = UIEdgeInsetsMake(10, 0, 10, 0);

Alternative, if you subclass UILabel, an example to this approach would be overriding the drawTextInRect method

(Objective-C)

- (void)drawTextInRect:(CGRect)uiLabelRect {
UIEdgeInsets myLabelInsets = {10, 0, 10, 0};
[super drawTextInRect:UIEdgeInsetsInsetRect(uiLabelRect, myLabelInsets)];
}

You could additionally provide your new subclassed UILabel with insets variables for TOP, LEFT, BOTTOM and RIGHT.

An example code could be:

In .h (Objective-C)

float topInset, leftInset,bottomInset, rightInset;

In .m (Objective-C)

- (void)drawTextInRect:(CGRect)uiLabelRect {
[super drawTextInRect:UIEdgeInsetsInsetRect(uiLabelRect, UIEdgeInsetsMake(topInset,leftInset,bottomInset,rightInset))];
}

From what I have seen, it seems you have to override the intrinsicContentSize of the UILabel when subclassing it.

So you should override intrinsicContentSize like:

- (CGSize) intrinsicContentSize {
CGSize intrinsicSuperViewContentSize = [super intrinsicContentSize] ;
intrinsicSuperViewContentSize.height += topInset + bottomInset ;
intrinsicSuperViewContentSize.width += leftInset + rightInset ;
return intrinsicSuperViewContentSize ;
}

And add the following method to edit your insets, instead of editing them individually:

- (void) setContentEdgeInsets:(UIEdgeInsets)edgeInsets {
topInset = edgeInsets.top;
leftInset = edgeInsets.left;
rightInset = edgeInsets.right;
bottomInset = edgeInsets.bottom;
[self invalidateIntrinsicContentSize] ;
}

It will update the size of your UILabel to match the edge insets and cover the multiline necessity you referred to.

After searching a bit I have found this Gist with an IPInsetLabel. If none of those solutions work you could try it out.

There was a similar question (duplicate) about this matter.

For a full list of available solutions, see this answer: UILabel text margin

Add left/right horizontal padding to UILabel

For a full list of available solutions, see this answer: UILabel text margin


Try subclassing UILabel, like @Tommy Herbert suggests in the answer to [this question][1]. Copied and pasted for your convenience:

I solved this by subclassing UILabel and overriding drawTextInRect: like this:

- (void)drawTextInRect:(CGRect)rect {
UIEdgeInsets insets = {0, 5, 0, 5};
[super drawTextInRect:UIEdgeInsetsInsetRect(rect, insets)];
}

How do I create padding around the text of a UILabel?

The code below does what you want (Create new LiveView playground and paste it).

But I provide it just for the sake of demonstration and consider that placing UILabel in the container and making proper constraints will be a proper solution for this task.

import UIKit
import PlaygroundSupport

class MyViewController : UIViewController {
override func loadView() {
let view = UIView()
view.backgroundColor = .white

let label = BorderedLabel()
label.frame = CGRect(x: 150, y: 200, width: 200, height: 20)
label.text = "Hello World!"
label.textColor = .black
// Border settings
label.layer.cornerRadius = 4
label.layer.borderColor = UIColor.black.cgColor
label.layer.borderWidth = 1
label.sizeToFit() // Important

view.addSubview(label)
self.view = view
}
}

class BorderedLabel: UILabel {
var sidePadding = CGFloat(10) // Needed padding, add property observers

override func sizeToFit() {
super.sizeToFit()
bounds.size.width += 2 * sidePadding
}

override func drawText(in rect: CGRect) {
print(rect)
super.drawText(in: rect.insetBy(dx: sidePadding, dy: 0))
invalidateIntrinsicContentSize()
}
}
// Present the view controller in the Live View window
PlaygroundPage.current.liveView = MyViewController()

However you can play with this solution and test it or improve convenience and reliability (along with Auto Layout support)



Related Topics



Leave a reply



Submit