Add left/right horizontal padding to UILabel
Asked Answered
M

13

71

I need to create a UILabel with a background color, and I'd like to add some left/right leading/trailing horizontal padding.

But every solution I've found seems like a nasty hack.

What is the 'standard' way to achieve this from iOS 5 forward?

A screenshot to illustrate my scenario:

left padding needed

Melatonin answered 17/10, 2013 at 21:24 Comment(6)
Why not set the label size to a specific value, and set the text alignment to right-justified?..Edie
Why you not creat your label just with CGRectMake(10,y,width,height) ?Fincher
Thanks, attached a screenshot to illustrate my problem. I want the label background to fill all width, but I need it left-justified. Sure I could add a view below with that color, but I'm just wondering why is a background color for labels if there's no way to add padding to the text.Melatonin
@incmiko, if my label rect starts in 10, then the dark green background will too.Melatonin
And for the latest on the space race ... You can precede it with a blank character, such as a standard ASCII space, or even a wide UNICODE space like "EM QUAD" or a really narrow one "THIN SPACE" or "HAIR SPACE". See my answer that includes a fairly comprehensive table of UNICODE spaces below.Autry
Possible duplicate of UILabel text marginIsia
K
95

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)];
}
Kisner answered 17/10, 2013 at 21:49 Comment(6)
this method returns void so there should be no return at the end of this method ;) Still works.Articulate
This is a good solution if you want to have yet one more subclass hanging around. While it is optimally flexible and reusable, it seems a bit cluttering and overkill for what most people will need. People may not be aware that UNICODE offers a substantial collection of spaces of various widths and can accommodate a padding for many common scenarios, without resulting to code-based solutions. See my answer for more info about that approach.Autry
@Allaboutthatbase2 I don't think Unicode characters will help if you need bottom and/or top padding. So you still need a code base solution even with your solution if you don't want to repeat yourself everywhere, you need to centralize this behavior.Maymaya
@florian - it is clearly not the ideal for every circumstance. But in a lot of cases it can be a big time saver, particularly when prototyping. As one who has noodled with graphical intricacies, bezier curve drawing and image filtering and processing and font manipulation and created my own fonts, I can say, I fully appreciate what you're saying.Autry
Had issues with auto layout, here is a solution that worked more completely for me: https://mcmap.net/q/23724/-resizing-a-uilabel-to-accommodate-insetsShredding
For Swift 4.x, use super.drawText(in: rect.inset(by: paddingInsets))Vizard
U
30

The most important part is that you must override both intrinsicContentSize() and drawTextInRect() in order to account for AutoLayout:

var contentInset: UIEdgeInsets = .zero {
    didSet {
        setNeedsDisplay()
    }
}

override public var intrinsicContentSize: CGSize {
    let size = super.intrinsicContentSize
    return CGSize(width: size.width + contentInset.left + contentInset.right, height: size.height + contentInset.top + contentInset.bottom)
}

override public func drawText(in rect: CGRect) {
    super.drawText(in: UIEdgeInsetsInsetRect(rect, contentInset))
}
Unbolt answered 20/4, 2016 at 7:21 Comment(0)
D
25

add a space character too the string. that's poor man's padding :)

OR

I would go with a custom background view but if you don't want that, the space is the only other easy options I see...

OR write a custom label. render the text via coretext

Dread answered 17/10, 2013 at 21:43 Comment(0)
P
23
#define PADDING 5

@interface MyLabel : UILabel

@end

@implementation MyLabel

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

- (CGRect)textRectForBounds:(CGRect)bounds
     limitedToNumberOfLines:(NSInteger)numberOfLines
{
    CGSize size = CGSizeMake(999, 999);
    CGRect rect = [self.attributedText
                   boundingRectWithSize:size
                                options:NSStringDrawingUsesLineFragmentOrigin
                                context:nil];
    return CGRectInset(rect, -PADDING, 0);
}

@end
Pyrrhic answered 27/1, 2014 at 9:50 Comment(1)
Is there any other solution then subclassing UILabel?Frisby
D
16
UIView* bg = [[UIView alloc]initWithFrame:CGRectMake(0, 0, self.frame.size.width, 70)];
bg.backgroundColor = [UIColor blackColor];
UILabel* yourLabel = [[UILabel alloc]initWithFrame:CGRectMake(10, y, yourWidth, yourHeight)];
[bg addSubview:yourLabel];

[self addSubview:bg];
Deflate answered 17/10, 2013 at 21:34 Comment(0)
A
16

Sometimes it's convenient to use UNICODE partial spaces to achieve alignment while prototyping. This can be handy in prototyping, proof-of-concept, or just to defer implementation of graphics algorithms.

If you use UNICODE spaces for convenience, be aware that at least one of the UNICODE spaces has a size based on the font it is displayed from, specifically the actual space character itself (U+0020, ASCII 32)

If you're using the default iOS system font in a UILabel, the default System font characteristics could change in a subsequent iOS release and suddenly introduce an unwanted misalignment by changing your app's precise spacing. This can and does happen, for example the "San Francisco" font replaced a previous iOS system font in an iOS release.

UNICODE easy to specify in Swift, for example:

let six_per_em_space = "\u{2006}"

Alternatively, cut/paste the space from an HTML page directly into the UILabel's text field in Interface Builder.

Note: Attached pic is a screenshot, not HTML, so visit the linked page if you want to cut/paste the space.

UNICODE spaces

Autry answered 11/2, 2015 at 0:42 Comment(0)
C
5

I had a couple of issues with the answers here, such as when you added in the padding, the width of the content was overflowing the box and that I wanted some corner radius. I solved this using the following subclass of UILabel:

#import "MyLabel.h"

#define PADDING 8.0
#define CORNER_RADIUS 4.0

@implementation MyLabel

- (void)drawRect:(CGRect)rect {
 self.layer.masksToBounds = YES;
 self.layer.cornerRadius = CORNER_RADIUS;
 UIEdgeInsets insets = {0, PADDING, 0, PADDING};
 return [super drawTextInRect:UIEdgeInsetsInsetRect(rect, insets)];
}
- (CGSize) intrinsicContentSize {
 CGSize intrinsicSuperViewContentSize = [super intrinsicContentSize] ;
 intrinsicSuperViewContentSize.width += PADDING * 2 ;
 return intrinsicSuperViewContentSize ;
}

@end

Hope that's helpful to someone! Note that if you wanted padding on the top and bottom, you would need to change this lines:

UIEdgeInsets insets = {0, PADDING, 0, PADDING};

To this:

UIEdgeInsets insets = {PADDING, PADDING, PADDING, PADDING};

And add this line underneath the similar one for width:

intrinsicSuperViewContentSize.height += PADDING * 2 ;
Cullis answered 14/9, 2015 at 14:58 Comment(0)
G
5

Swift 5

Create below class file and set it to your label as custom class name through storyboard. That's it.

class PaddingLabel: UILabel {

    override func drawText(in rect: CGRect) {
        let insets = UIEdgeInsets(top: 0, left: 8, bottom: 0, right: 0)//CGRect.inset(by:)
        super.drawText(in: rect.inset(by: insets))
    }
}
Galengalena answered 3/5, 2019 at 9:33 Comment(1)
what should be i pass in rect while calling method ?Neolatin
S
4

If you want to add padding to UILabel but not want to subclass it you can put your label in a UIView and give paddings with autolayout like:

Padding with UIView and autolayout

Result:

Result

Schwitzer answered 6/7, 2017 at 10:22 Comment(0)
O
1

Subclass UILabel and override drawTextInRect: like this:

- (void)drawTextInRect:(CGRect)rect 
{
    UIEdgeInsets insets = {0, 10, 0, 0};
    return [super drawTextInRect:UIEdgeInsetsInsetRect(rect, insets)];
}
Odoacer answered 17/10, 2013 at 21:53 Comment(0)
M
1

One thing I did to overcome this issue was to use a UIButton instead of a UILabel. Then in the Attributes Inspector of the Interface Builder, I used the Edge for the Title as the padding.
If you do not attach the button to an action, when clicked it will not get selected but it will still show the highlight.

You can also do this programmatically with the following code:

UIButton *mButton = [[UIButton alloc] init];
[mButton setTitleEdgeInsets:UIEdgeInsetsMake(top, left, bottom, right)];
[mButton setTitle:@"Title" forState:UIControlStateNormal];
[self.view addSubView:mButton];

This approach gives the same result but sometimes it did not work for some reason that I did not investigate since if possible I use the Interface Builder.

This is still a workaround but it works quite nicely if the highlight doesn't bother you. Hope it is useful

Magen answered 2/1, 2015 at 11:11 Comment(1)
One must not use a UIButton as a UILabel; these have completely different use cases and come with a different set of functionalities.Purple
M
0

Installation with CocoaPods

pod 'PaddingLabel', '1.2'

Change your UILabel class to PaddingLabel ###Example

Specify padding

enter image description here

Mooneyham answered 19/8, 2020 at 21:31 Comment(0)
C
-1

If you need a more specific text alignment than what adding spaces to the left of the text provides, you can always add a second blank label of exactly how much of an indent you need.

I've got buttons with text aligned left with an indent of 10px and needed a label below to look in line. It gave the label with text and left alignment and put it at x=10 and then made a small second label of the same background color with a width = 10, and lined it up next to the real label.

Minimal code and looks good. Just makes AutoLayout a little more of a hassle to get everything working.

Currey answered 23/4, 2014 at 18:58 Comment(1)
If you're adding a second blank label to the left of the existing label, you might as well override sizeThatFits or use auto layout.Purple

© 2022 - 2024 — McMap. All rights reserved.