为UILabel添加左/右水平内边距

70

我需要创建一个带有背景颜色的UILabel,并且我想添加一些左/右前导/尾随水平填充。

但是我找到的每个解决方案都像是一个恶心的hack。

从iOS 5开始,有什么“标准”方法来实现这一点?

以下是一个截图来说明我的情况:

需要左填充


为什么不将标签大小设置为特定值,并将文本对齐方式设置为右对齐呢? - Sergey Kalinichenko
为什么你不用CGRectMake(10,y,width,height)直接创建你的标签? - Magyar Miklós
3
谢谢,我附上一张截图来说明我的问题。我希望标签背景填满整个宽度,但是需要左对齐。我可以添加一个具有相同颜色的视图在下方,但我只是想知道为什么标签有背景色,却没有办法给文本添加内边距。 - ssantos
@incmiko,如果我的标签矩形从10开始,那么深绿色背景也会从10开始。 - ssantos
关于太空竞赛的最新消息...您可以在前面加上一个空格字符,例如标准ASCII空格,甚至是宽的UNICODE空格,如“EM QUAD”,或者非常窄的“THIN SPACE”或“HAIR SPACE”。请参见我的答案,其中包括一个相当全面的UNICODE空格表。 - clearlight
可能是UILabel文本边距的重复问题。 - gblazex
13个回答

95

要获取所有可用的解决方案,请参见此回答:UILabel文本边距


尝试对UILabel进行子类化,就像@Tommy Herbert在[这个问题][1]的回答中建议的那样。以下为复制并粘贴的代码,以方便您使用:

我通过对UILabel进行子类化并重写drawTextInRect来解决了这个问题,代码如下:

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

3
这个方法返回 void,因此在该方法末尾不应有返回值 ;) 然而,它仍然能正常工作。 - Tomasz Szulc
如果你想再增加一个子类,这是一个不错的解决方案。虽然它具有最大的灵活性和可重用性,但对于大多数人所需的功能来说,似乎有点凌乱和过度。人们可能不知道UNICODE提供了各种宽度的空格集合,并且可以适应许多常见情况的填充,而不需要使用基于代码的解决方案。有关该方法的更多信息,请查看我的答案。 - clearlight
1
@Allaboutthatbase2,我认为Unicode字符在需要底部和/或顶部填充时并没有帮助。因此,即使您有解决方案,如果您不想在每个地方重复自己,仍然需要一个代码库解决方案,您需要将此行为集中化。 - grandouassou
@florian - 显然并非每种情况下都是理想选择。但在许多情况下,它确实可以节省大量时间,特别是在原型设计阶段。作为一个曾经涉足图形细节、贝塞尔曲线绘制、图像过滤和处理以及字体操作并创建自己的字体的人,我可以说我完全理解你的观点。 - clearlight
我在auto layout方面遇到了问题,这里有一个对我完全有效的解决方案:https://dev59.com/EmEi5IYBdhLWcg3wjs5j#21267507 - Joe
1
对于Swift 4.x,请使用super.drawText(in: rect.inset(by: paddingInsets)) - parag

30

最重要的部分是,您必须覆盖intrinsicContentSize()drawTextInRect()这两个方法以考虑自动布局:

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))
}

25

在字符串中添加一个空格字符,这就是“穷人的填充” :)

或者

我会选择自定义背景视图,但如果您不想要那样,我只能看到其他简单的选项是使用空格...

或者编写自定义标签。通过coretext呈现文本。


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

5
除了子类化UILabel,还有其他解决方案吗? - BSKANIA

16
有时在原型设计时,使用UNICODE部分空格实现对齐是很方便的。这在原型设计、概念验证或仅用于推迟图形算法实现时非常方便。
如果您为了方便而使用UNICODE空格,请注意至少有一个UNICODE空格的大小取决于其所显示的字体,特别是实际空格字符本身(U+0020,ASCII 32)。
如果您在UILabel中使用默认的iOS系统字体,则默认的系统字体特征可能会在随后的iOS版本中更改,并通过改变应用程序的精确间距而突然引入不需要的错位。例如,“San Francisco”字体取代了iOS中以前的系统字体。
在Swift中指定UNICODE很容易,例如:
let six_per_em_space = "\u{2006}"

或者,直接从 HTML 页面中将空格复制/粘贴到 Interface Builder 中的 UILabel 文本字段中。

注:附带的图片是截图,不是HTML,所以如果要剪切/粘贴空格,请访问链接页面

UNICODE spaces


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];

5

Swift 5

创建以下类文件并通过故事板将其设置为标签的自定义类名称即可。就是这样。

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))
    }
}

在调用方法时,我应该传递什么参数给矩形(rect)? - Nirav Kotecha

5

我看到这里有一些问题,例如当添加填充时,内容的宽度会溢出框,并且我想要一些圆角。我使用以下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

希望这对某些人有所帮助!请注意,如果你想在顶部和底部增加填充,你需要更改这些行:
UIEdgeInsets insets = {0, PADDING, 0, PADDING};

转换为:

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

在宽度的相似行下面添加这一行:

intrinsicSuperViewContentSize.height += PADDING * 2 ;

4
如果您想要为UILabel添加填充,但不想对其进行子类化,可以将标签放入UIView中,并使用自动布局提供填充,如下所示:

Padding with UIView and autolayout

结果如下图所示:

Result


2

我为了解决这个问题,使用了UIButton代替UILabel。然后在Interface Builder的Attributes Inspector中,将Title的Edge用作填充。


如果您不将按钮附加到操作,则单击时它不会被选中,但仍会显示高亮。

您也可以使用以下代码以编程方式完成此操作:

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

这种方法可以得到相同的结果,但有时候由于某些原因它不起作用,我没有进行调查,因为如果可能的话我会使用Interface Builder。

这仍然是一种解决办法,但如果高亮不影响您的话,它可以很好地工作。希望这有用。


1
不能将 UIButton 用作 UILabel;它们具有完全不同的用例和不同的功能集。 - Zorayr

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接