Uilabel Text Margin

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

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 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.

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.

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)

Text padding on UILabel

Try calling invalidateIntrinsicContentSize:

var padding: UIEdgeInsets = UIEdgeInsets.zero {
didSet {
self.invalidateIntrinsicContentSize()
}
}

EDIT:

I have tried different options. If you update the frame size with the intrinsicContentSize in layoutSubviews that make the trick but I don't know if there is a better way to do it:

override func layoutSubviews() {
super.layoutSubviews()
self.frame.size = self.intrinsicContentSize
}

Xcode: How to add margin/padding to label text?

If you want to go the layout constraints route, this is probably the fitting solution for you:

You should use a container view and place the label inside of that. Then add constraints for the label, which will be equivalent to a padding.

Sample Image

Select the label and click the constraints panel at the bottom right in the Storyboard file.

Label's constraints to container view

With the label selected, apply layout constraints like seen above (make sure you select the red "lines" so that the constraints are actually applied).

End result

The orange view is the container view. The label is right inside of that.



Related Topics



Leave a reply



Submit