如何向 UIButton 添加多行文本?

Posted

技术标签:

【中文标题】如何向 UIButton 添加多行文本?【英文标题】:How do you add multi-line text to a UIButton? 【发布时间】:2010-10-10 22:00:31 【问题描述】:

我有以下代码...

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

...我的想法是我可以为按钮设置多行文本,但文本总是被 UIButton 的 backgroundImage 遮挡。显示按钮子视图的日志调用显示已添加 UILabel,但无法看到文本本身。这是 UIButton 中的错误还是我做错了什么?

【问题讨论】:

button.titleLabel?.numberOfLines = 0 注意这个非常古老的 QA,在现代 Xcode 中非常简单,选择“ATTRIBUTED TEXT” 然后很简单,选择“字符换行”。 另见updated answer 类似问题。 看到这个答案(多行,适合宽度,适合高度)按钮文本***.com/a/59211399/7523163 ios 15 现已免费提供此功能⟹ developer.apple.com/videos/play/wwdc2021/10059/?time=641 ???? 【参考方案1】:

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

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

附:我测试了设置 titleLabel?.textAlignment 不是必需的,并且标题在 .natural 中对齐。

【讨论】:

【参考方案2】:

在 2021 年的 iOS 15 中,Apple 首次通过 UIButton.Configuration API 正式支持多行 UIButtons。

UIButton.Configuration

指定按钮及其内容的外观和行为的配置。

What's new in UIKit 以及会话中探索了这个新 API:

满足 UIKit 按钮系统

每个应用程序都使用按钮。在 iOS 15 中,您可以采用更新的样式来创建精美的按钮,轻松融入您的界面。我们将探索可让您更轻松地创建不同类型按钮的功能,了解如何提供更丰富的交互,并了解如何在使用 Mac Catalyst 时获得出色的按钮。

https://developer.apple.com/videos/play/wwdc2021/10064/

【讨论】:

...以及如何使用UIButtton.Configuration 实现多行功能?【参考方案3】:

添加按钮约束和子视图。这就是我在我的项目中的做法,让我们说这样更容易。我实际上 99% 的时间都以编程方式制作所有内容。因为这对我来说更容易。故事板有时真的很麻烦 [1]:https://i.stack.imgur.com/5ZSwl.png

【讨论】:

【参考方案4】:

Swift 5 , UIButton 中的多行文本

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

【讨论】:

【参考方案5】:

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

【讨论】:

【参考方案6】:

我遇到了自动布局的问题,启用多行后结果如下: 所以titleLabel 大小不会影响按钮大小 我基于contentEdgeInsets 添加了Constraints(在这种情况下 contentEdgeInsets 是 (10, 10, 10, 10) 打电话后makeMultiLineSupport(): 希望对您有所帮助(swift 5.0):

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() guard let titleLabel = titleLabel else return titleLabel.textAlignment = .center 我发现没有必要添加约束,只需在设置 lineBreakMode/textAlignment/numberOfLines 后设置文本即可。并为顶部和底部插入设置 titleEdgeInsets。 @BillChan 不幸的是,这并不适用于所有情况 正如所写,这些约束每次都会导致自动布局冲突。虽然我还不能 100% 确定使用不等式约束的重要性,但我确实知道其中 2 个约束写错了:底部和右侧边缘应该使用 relatedBy: .lessThanOrEqual 并翻转常量负值 constant: -contentEdgeInsets.bottom|right跨度> 谢谢 - 由于不可见字符,我在最后一行有一个 ...,所以我添加了 .lineBreakMode = .byClipping【参考方案7】:

如今,如果您真的需要在界面构建器中逐个访问此类内容,您可以使用如下简单的扩展来实现:

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

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

【讨论】:

【参考方案8】:

在 Xcode 9.3 中,您可以使用 storyboard 来实现,如下所示,

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

button.titleLabel?.textAlignment = .center

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

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

只需设置标题,

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

这是结果,

【讨论】:

myButton.titleLabel.textAlignment = NSTextAlignmentCenter 声明也是需要的。【参考方案9】:

我将jessecurry's answer 合并到STAButton 中,这是我的STAControls 开源库的一部分。我目前在我正在开发的一个应用程序中使用它,它可以满足我的需求。随时打开有关如何改进它的问题或向我发送拉取请求。

【讨论】:

【参考方案10】:

斯威夫特 4.0

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

【讨论】:

【参考方案11】:

您必须添加此代码:

buttonLabel.titleLabel.numberOfLines = 0;

【讨论】:

【参考方案12】:

对于 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 前版

一般来说,只需做这两件事:

    选择“属性文本” 在“换行符”弹出窗口中选择“自动换行”

【讨论】:

请注意,这些分配在 iOS 6 中已弃用。请参阅@NiKKi 下面的答案以获取更新的语法。 让人们知道:如果您使用 NSAttributedString,这将不起作用 其实只要加上button.titleLabel.numberOfLines = 0;这将使线路无限。和 button.titleLabel.textAlignment = NSTextAlignmentLeft;如果你想要左对齐文本,因为标题默认居中。 迅速button.titleLabel?.lineBreakMode = NSLineBreakMode.ByWordWrapping 感谢@Robert 的快速解决方案。也可以使用推理并省略NSLineBreakMode,例如:button.titleLabel?.lineBreakMode = .ByWordWrapping【参考方案13】:
self.btnError.titleLabel?.lineBreakMode = NSLineBreakMode.byWordWrapping

self.btnError.titleLabel?.textAlignment = .center

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

【讨论】:

【参考方案14】:

SWIFT 3

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

【讨论】:

【参考方案15】:

如果您使用自动布局。

button.titleLabel?.adjustsFontSizeToFitWidth = true
button.titleLabel?.numberOfLines = 2

【讨论】:

【参考方案16】:

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

[]

【讨论】:

您能否添加有关如何实现此目的的文字说明。图片很棒,但如果它变得不可用,您的答案将毫无用处。 @RoryMcCrossan 嗨,我在上面添加了一张图片。你能看吗?请注意,Xcode 7 仍然存在问题,因此按钮标题可能会消失。但是,一旦您运行该应用程序,您将获得所需的结果。 实际上,这是该线程中的最佳答案。立即工作并显示来自 IB 的居中文本。谢谢! @user5440039 感谢您的出色回答。无需添加文字说明。【参考方案17】:

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

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

注意

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

【讨论】:

【参考方案18】:

重申 Roger Nolan 的建议,但使用明确的代码,这是一般解决方案:

button.titleLabel?.numberOfLines = 0

【讨论】:

大声笑,这个解决方案太完美了。谢谢!【参考方案19】:

选择的答案是正确的,但如果你更喜欢在 Interface Builder 中做这种事情,你可以这样做:

【讨论】:

感谢我 24 岁的自己写下这个答案,来自 28 岁的自己。 为了保持仅使用 Interface Builder 的设置,应在 User Defined Runtime Attributed 中将 titleLabel.textAlignmentNumber 值设置为 1 以使文本居中 感谢 24 岁的自己,感谢 28 岁的自己! 感谢30岁的自己,感谢27岁的自己!【参考方案20】:

在 iOS7 上使用自动布局左对齐:

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

【讨论】:

【参考方案21】:

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

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

【讨论】:

【参考方案22】:

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

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

HTH

【讨论】:

【参考方案23】:

有一个更简单的方法:

someButton.lineBreakMode = UILineBreakModeWordWrap;

(为 iOS 3 及更高版本编辑:)

someButton.titleLabel.lineBreakMode = UILineBreakModeWordWrap;

【讨论】:

UIButton.lineBreakMode 在 3.0 中已被弃用,所以这不再是一个好的选择。 lineBreakMode 仅作为 UIButton 的直接属性不推荐使用。我们被定向到“改用 titleLabel 的 lineBreakMode 属性”。我相应地编辑了 Valerii 的答案。这仍然是一个不错的选择。【参考方案24】:

对于 IOS 6:

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

作为

UILineBreakModeWordWrap and UITextAlignmentCenter

在 IOS 6 以后已弃用..

【讨论】:

NSText.hFoundation 内没有添加弃用。它从 6.0 开始可用,但未弃用。 迅速:button.titleLabel?.lineBreakMode = NSLineBreakMode.ByWordWrapping button.titleLabel?.textAlignment = NSTextAlignment.Center【参考方案25】:

对于那些使用 Xcode 4 故事板的人,您可以单击按钮,然后在右侧的实用工具窗格中的属性检查器下,您将看到换行符选项。选择自动换行,你应该很高兴。

【讨论】:

【参考方案26】:

效果很好。

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

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

【讨论】:

【参考方案27】:

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

【讨论】:

【参考方案28】:

至于 Brent 将标题 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;

我确实花时间写了更多关于here 的内容。在那里,我还指出了一个较短的解决方案,尽管它并不完全适合所有场景并且涉及一些私人视图黑客攻击。此外,您还可以下载一个可供使用的 UIButton 子类。

【讨论】:

【参考方案29】:

虽然可以将子视图添加到控件,但不能保证它会真正起作用,因为控件可能不希望它存在,因此可能表现不佳。如果你能摆脱它,只需将标签添加为按钮的兄弟视图并设置其框架,使其与按钮重叠;只要它被设置为出现在按钮的顶部,按钮所能做的任何事情都不会掩盖它。

换句话说:

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

【讨论】:

拜托,如果你建议这种丑陋的方法,至少不要在你的代码示例中出错:)。如果标签是子视图,则标签不应与按钮具有相同的中心。使用 myLabel.frame = button.bounds;或 myLabel.center = cgPointMake(button.frame.size.with*0.5,button.frame.size.height*0.5) @GrizzlyNetch 我特别建议 ​​not 将其添加为按钮的子视图。 addSubview: 这里将其添加到button 的超级视图中,从而使其成为按钮的兄弟,因此匹配它们的中心是正确的。 啊,我的错!你是对的,我错过了超级视图中的“小”事实:D ...对不起:) 这不是所要求的,由于元素按钮具有标题,因此该解决方案将是实现问题的不好方法。 这在 iPhone OS 2.0 中是合理的建议。现在有很多更好的方法可以做到这一点。 :^)【参考方案30】:

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

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

【讨论】:

我知道 title 属性,但据我所知,不可能将其设置为使用多行,因此采用了这种方法。如果我禁用了 backgroundImage,我的 UILabel 就会出现,这对我来说暗示了一个 bug,无论是bringSubviewToFront 还是 UIButton 本身。

以上是关于如何向 UIButton 添加多行文本?的主要内容,如果未能解决你的问题,请参考以下文章

根据文本内部的长度,UIButton不会垂直增长

在多行 UIButton 的文本中查找字母的运行时位置

UIButton 的渐变未显示

如何滚动到 UIScrollview 中的 UIButton 位置

如何向 UIButton 添加阴影?

如何制作UIButton的文本对齐中心?使用IB