如何将多行文本添加到UIButton?


368

我有以下代码...

UILabel *buttonLabel = [[UILabel alloc] initWithFrame:targetButton.bounds];
buttonLabel.text = @"Long text string";
[targetButton addSubview:buttonLabel];
[targetButton bringSubviewToFront:buttonLabel];

...这个想法是我可以为按钮设置多行文本,但是该文本始终被UIButton的backgroundImage遮盖。显示该按钮的子视图的日志记录调用表明已添加UILabel,但看不到文本本身。这是UIButton中的错误还是我做错了什么?


7
button.titleLabel?.numberOfLines = 0
ma11hew28

2
请注意这个非常古老的质量检查,在现代Xcode中非常简单,选择“属性文本”,然后选择“字符换行”即可。
Fattie

另请参阅对类似问题的更新答案
ToolmakerSteve

请参见按钮文字的此答案(多行,适合宽度,适合高度)stackoverflow.com/a/59211399/7523163
Hamid Reza Ansari

Answers:


675

对于iOS 6及更高版本,请使用以下命令允许多行:

button.titleLabel.lineBreakMode = NSLineBreakByWordWrapping;
// you probably want to center it
button.titleLabel.textAlignment = NSTextAlignmentCenter; // if you want to 
[button setTitle: @"Line1\nLine2" forState: UIControlStateNormal];

对于iOS 5及以下版本,请使用以下内容允许多行:

button.titleLabel.lineBreakMode = UILineBreakModeWordWrap;
// you probably want to center it
button.titleLabel.textAlignment = UITextAlignmentCenter;
[button setTitle: @"Line1\nLine2" forState: UIControlStateNormal];

2017年,对于iOS9向前版本

通常,只需执行以下两项操作:

  1. 选择“属性文字”
  2. 在“换行符”弹出窗口中,选择“自动换行”

5
请注意,iOS 6中已弃用了这些分配。有关更新的语法,请参阅下面的@NiKKi答案。
亚伦·布拉格2013年

6
就是这样,人们知道:如果您使用的是NSAttributedString,这将不起作用

29
实际上,只需添加button.titleLabel.numberOfLines = 0; 这将使行数不受限制。和button.titleLabel.textAlignment = NSTextAlignmentLeft; 如果要保留左对齐文本,因为标题默认居中。
RyJ

4
迅速button.titleLabel?.lineBreakMode = NSLineBreakMode.ByWordWrapping
罗伯特

1
感谢@Robert提供快速解决方案。也可以使用推断并省略NSLineBreakMode,例如:button.titleLabel?.lineBreakMode = .ByWordWrapping
mjswensen

145

所选答案是正确的,但是如果您更喜欢在Interface Builder中执行这种操作,则可以执行以下操作:

图片


58
多亏了我24岁的我写的答案,来自28岁的我。
亚当·怀特

5
而留在Interface Builder中唯一设置,应设置titleLabel.textAlignmentNumber价值,1User Defined Runtime Attributed使文字居中
AnthoPak

2
感谢您来自我24岁的我28岁的我!
丹尼尔·斯普林格

59

如果要添加标题以多行居中的按钮,请设置按钮的Interface Builder设置:

[ 这里]


您能否添加有关如何实现此目标的文字说明。图像很棒,但是如果图像不可用,您的答案将毫无用处。
罗里·麦克罗斯

1
@RoryMcCrossan嗨,我在上面添加了一张图片。你看得到吗?请注意,Xcode 7仍然存在问题,因此按钮标题可能会消失。但是,一旦运行该应用程序,您将获得所需的结果。
user5440039 2015年

2
实际上,这是该线程中的最佳答案。立即工作并显示IB的居中文本。谢谢!
RainCast

@ user5440039感谢您的出色回答。无需添加文字说明。
Fattie

54

对于IOS 6:

button.titleLabel.lineBreakMode = NSLineBreakByWordWrapping;
button.titleLabel.textAlignment = NSTextAlignmentCenter;

UILineBreakModeWordWrap and UITextAlignmentCenter

从IOS 6开始不推荐使用。


里面NSText.hFoundation有没有废弃的加入。它从6.0起可用,但尚未弃用。
Alex Cio

迅速:button.titleLabel?.lineBreakMode = NSLineBreakMode.ByWordWrapping button.titleLabel?.textAlignment = NSTextAlignment.Center
jcity

30

为了重申罗杰·诺兰的建议,但使用显式代码,这是一般的解决方案:

button.titleLabel?.numberOfLines = 0

21

SWIFT 3

button.titleLabel?.lineBreakMode = .byWordWrapping
button.titleLabel?.textAlignment = .center  
button.setTitle("Button\nTitle",for: .normal)

13

在Xcode 9.3中,您可以使用以下情节提要来做到这一点,

在此处输入图片说明

您需要将按钮标题textAlignment设置为居中

button.titleLabel?.textAlignment = .center

您不需要像下面这样用新行(\ n)设置标题文本,

button.setTitle("Good\nAnswer",for: .normal)

只需设置标题,

button.setTitle("Good Answer",for: .normal)

结果是这样

在此处输入图片说明


myButton.titleLabel.textAlignment = NSTextAlignmentCenter也需要声明。
tounaobun

11

有一种更简单的方法:

someButton.lineBreakMode = UILineBreakModeWordWrap;

(针对iOS 3及更高版本进行编辑:)

someButton.titleLabel.lineBreakMode = UILineBreakModeWordWrap;

4
UIButton.lineBreakMode在3.0中已弃用,因此不再是一个好的选择。
Christopher Pickslay 2011年

2
不建议将lineBreakMode用作UIButton的直接属性。我们被定向为“改为使用titleLabel的lineBreakMode属性。” 我相应地编辑了Valerii的答案。仍然是一个不错的选择。
维也纳,2012年

11

在iOS7上通过自动布局向左对齐:

button.titleLabel.lineBreakMode = NSLineBreakByWordWrapping;
button.titleLabel.textAlignment = NSTextAlignmentLeft;
button.contentHorizontalAlignment = UIControlContentHorizontalAlignmentLeft;

9

我在自动布局方面遇到问题,启用多行后,结果是这样的: 因此大小不会影响 我基于添加的按钮大小(在这种情况下,contentEdgeInsets为(10,10,10,10 ): 致电后 希望对您有所帮助(5.0版):
在此处输入图片说明
titleLabel
ConstraintscontentEdgeInsets
makeMultiLineSupport()
在此处输入图片说明

extension UIButton {

    func makeMultiLineSupport() {
        guard let titleLabel = titleLabel else {
            return
        }
        titleLabel.numberOfLines = 0
        titleLabel.setContentHuggingPriority(.required, for: .vertical)
        titleLabel.setContentHuggingPriority(.required, for: .horizontal)
        addConstraints([
            .init(item: titleLabel,
                  attribute: .top,
                  relatedBy: .greaterThanOrEqual,
                  toItem: self,
                  attribute: .top,
                  multiplier: 1.0,
                  constant: contentEdgeInsets.top),
            .init(item: titleLabel,
                  attribute: .bottom,
                  relatedBy: .greaterThanOrEqual,
                  toItem: self,
                  attribute: .bottom,
                  multiplier: 1.0,
                  constant: contentEdgeInsets.bottom),
            .init(item: titleLabel,
                  attribute: .left,
                  relatedBy: .greaterThanOrEqual,
                  toItem: self,
                  attribute: .left,
                  multiplier: 1.0,
                  constant: contentEdgeInsets.left),
            .init(item: titleLabel,
                  attribute: .right,
                  relatedBy: .greaterThanOrEqual,
                  toItem: self,
                  attribute: .right,
                  multiplier: 1.0,
                  constant: contentEdgeInsets.right)
            ])
    }

}

在swift 5中完美运行。我还添加了功能,使按钮中的文本居中。func centerTextInButton(){保护let titleLabel = titleLabel else {return} titleLabel.textAlignment = .center}
ShadeToD

谢谢。那是一个很好的解决方案。
梯队

我发现添加约束不是必需的,只需在设置lineBreakMode / textAlignment / numberOfLines之后设置文本即可。还要为顶部和底部插图设置titleEdgeInsets。
比尔·陈

不幸的是,@ BillChan并非在所有情况下都有效
Amir Khorsandi

7

首先,您应该知道UIButton里面已经有一个UILabel。您可以使用设置它–setTitle:forState:

您的示例的问题在于,您需要将UILabel的numberOfLines属性设置为默认值1以外的其他值。您还应该查看该lineBreakMode属性。


我知道title属性,但是据我所知,不可能将其设置为使用多行,因此是这种方法。如果禁用backgroundImage,则会显示我的UILabel,对我来说,这表明BringSubviewToFront或UIButton本身存在错误。
Owain Hunt,2009年

4

对于使用Xcode 4故事板的用户,可以单击按钮,然后在Attributes Inspector下的Utilities窗格的右侧,将看到一个Line Break选项。选择自动换行,您应该一切顺利。


4

这里的答案告诉您如何以编程方式实现多行按钮标题。

我只是想补充一下,如果您使用情节提要,则可以键入[Ctrl + Enter]来在按钮标题字段上强制换行。

高温超导



3

关于布伦特将标题UILabel用作同级视图的想法,在我看来,这不是一个很好的想法。我一直在思考与UILabel的交互问题,因为它的触摸事件没有通过UIButton的视图。

另一方面,将UILabel作为UIButton的子视图,我很舒服地知道触摸事件将始终传播到UILabel的父视图。

我确实采用了这种方法,并且没有注意到backgroundImage报告的任何问题。我将此代码添加到了UIButton子类的-titleRectForContentRect:中,但是该代码也可以放置在UIButton超级视图的绘制例程中,在这种情况下,您应将所有对self的引用替换为UIButton的变量。

#define TITLE_LABEL_TAG 1234

- (CGRect)titleRectForContentRect:(CGRect)rect
{   
    // define the desired title inset margins based on the whole rect and its padding
    UIEdgeInsets padding = [self titleEdgeInsets];
    CGRect titleRect = CGRectMake(rect.origin.x    + padding.left, 
                                  rect.origin.x    + padding.top, 
                                  rect.size.width  - (padding.right + padding.left), 
                                  rect.size.height - (padding.bottom + padding].top));

    // save the current title view appearance
    NSString *title = [self currentTitle];
    UIColor  *titleColor = [self currentTitleColor];
    UIColor  *titleShadowColor = [self currentTitleShadowColor];

    // we only want to add our custom label once; only 1st pass shall return nil
    UILabel  *titleLabel = (UILabel*)[self viewWithTag:TITLE_LABEL_TAG];


    if (!titleLabel) 
    {
        // no custom label found (1st pass), we will be creating & adding it as subview
        titleLabel = [[UILabel alloc] initWithFrame:titleRect];
        [titleLabel setTag:TITLE_LABEL_TAG];

        // make it multi-line
        [titleLabel setNumberOfLines:0];
        [titleLabel setLineBreakMode:UILineBreakModeWordWrap];

        // title appearance setup; be at will to modify
        [titleLabel setBackgroundColor:[UIColor clearColor]];
        [titleLabel setFont:[self font]];
        [titleLabel setShadowOffset:CGSizeMake(0, 1)];
        [titleLabel setTextAlignment:UITextAlignmentCenter];

        [self addSubview:titleLabel];
        [titleLabel release];
    }

    // finally, put our label in original title view's state
    [titleLabel setText:title];
    [titleLabel setTextColor:titleColor];
    [titleLabel setShadowColor:titleShadowColor];

    // and return empty rect so that the original title view is hidden
    return CGRectZero;
}

我花了时间,在这里写了一些更多的文章。在这里,我还指出了一个较短的解决方案,尽管它并不完全适合所有情况,并且涉及一些私密视图黑客。您还可以在此处下载准备使用的UIButton子类。


3

如果您在iOS 6上使用自动布局,则可能还需要设置preferredMaxLayoutWidth属性:

button.titleLabel.lineBreakMode = NSLineBreakByWordWrapping;
button.titleLabel.textAlignment = NSTextAlignmentCenter;
button.titleLabel.preferredMaxLayoutWidth = button.frame.size.width;

3

将lineBreakMode设置为NSLineBreakByWordWrapping(在IB或代码中)会使按钮标签变为多行,但不会影响按钮的框架。

如果按钮具有动态标题,则有一个技巧:使用相同的字体放置隐藏的UILabel并将其高度与布局的按钮高度相关联;当将文本设置为按钮,标签和自动布局将完成所有工作。

注意

单行按钮的固有尺寸高度大于标签的高度,因此,为防止标签的高度缩小,它的垂直内容拥抱优先级必须大于按钮的垂直内容压缩阻力。


3

Swift 5.0Xcode 10.2中

//UIButton extension
extension UIButton {
     //UIButton properties
     func btnMultipleLines() {
         titleLabel?.numberOfLines = 0
         titleLabel?.lineBreakMode = .byWordWrapping
         titleLabel?.textAlignment = .center        
     }
}

在您的ViewController调用中,像这样

button.btnMultipleLines()//This is your button

2

它运作完美。

添加以与配置文件(例如Plist)一起使用时,您需要使用CDATA编写多行标题,如下所示:

<string><![CDATA[Line1
Line2]]></string>


2

迅捷4.0

btn.titleLabel?.lineBreakMode = .byWordWrapping
btn.titleLabel?.textAlignment = .center
btn.setTitle( "Line1\nLine2", for: .normal)

2

这些天来,如果您确实需要根据情况视情况在Interface Builder中访问这种事情,则可以使用一个简单的扩展来实现,例如:

extension UIButton {
    @IBInspectable var numberOfLines: Int {
        get { return titleLabel?.numberOfLines ?? 1 }
        set { titleLabel?.numberOfLines = newValue }
    }
}

然后,您可以简单地将numberOfLines设置为任何UIButton或UIButton子类上的属性,就好像它是一个标签一样。其他许多通常无法访问的值也是如此,例如视图图层的角半径或它投射的阴影的属性。


2

Swift 5,用于UIButton中的多行文本

  let button = UIButton()
  button.titleLabel?.lineBreakMode = .byWordWrapping
  button.titleLabel?.textAlignment = .center
  button.titleLabel?.numberOfLines = 0 // for Multi line text

0

滚动自己的按钮类。从长远来看,这是迄今为止最好的解决方案。UIButton和其他UIKit类在如何自定义它们方面有严格的限制。


0
self.btnError.titleLabel?.lineBreakMode = NSLineBreakMode.byWordWrapping

self.btnError.titleLabel?.textAlignment = .center

self.btnError.setTitle("Title", for: .normal)

0

我将jesscurry的答案纳入了STAButton,它是我的STAControls开源库的一部分。我目前在正在开发的其中一个应用程序中使用它,它可以满足我的需求。随意打开有关如何改进它或向我发送请求请求的问题。


0

要将标题标签的间距固定到按钮,请 setTitle 之前设置titleEdgeInsets和其他属性:

    let set = UIButton()
    sut.titleLabel?.lineBreakMode = .byWordWrapping
    sut.titleLabel?.numberOfLines = 0
    sut.titleEdgeInsets = UIEdgeInsets(top: 10, left: 10, bottom: 20, right: 20)
    sut.setTitle("Dummy button with long long long long long long long long title", for: .normal)

PS我测试了设置titleLabel?.textAlignment的必要性,并且标题与对齐.natural


-4

尽管可以将子视图添加到控件中,但是不能保证它会真正起作用,因为控件可能不希望它存在于其中并且因此可能表现不佳。如果可以避免,则只需将标签添加为按钮的同级视图,然后设置其框架以使其与按钮重叠;只要将其设置为显示在按钮顶部,该按钮所能做的任何事情都不会掩盖它。

换一种说法:

[button.superview addSubview:myLabel];
myLabel.center = button.center;

2
请,如果您建议这种丑陋的方法,至少不要在您的代码示例中犯错误:)。如果标签是子视图,则标签的中心不应与按钮的中心相同。使用myLabel.frame = button.bounds; 或myLabel.center = cgPointMake(button.frame.size.with * 0.5,button.frame.size.height * 0.5)
JakubKnejzlik 2014年

1
@GrizzlyNetch我特别建议不要将其添加为按钮的子视图。addSubview:此处将其添加到button的超级视图中,从而使其成为按钮的同级,因此匹配其中心是正确的。
布伦特皇家戈登

啊,我的错!您是对的,我已经错过了它在
超级

并不是完全要问这个问题,因为元素按钮具有标题,所以该解决方案将是实现该问题的一种不好的方法。
Pablo Blanco

在iPhone OS 2.0中,这是合理的建议。到目前为止,有更好的方法可以做到这一点。:^)
布伦特皇家-戈登
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.