【问题标题】:How do you add multi-line text to a UIButton?如何向 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 中的错误还是我做错了什么?

【问题讨论】:

标签: ios objective-c cocoa-touch uibutton uikit


【解决方案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 前版

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

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

                  【讨论】:

                  • 请注意,这些分配在 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 本身。
                                        猜你喜欢
                                        • 1970-01-01
                                        • 1970-01-01
                                        • 1970-01-01
                                        • 1970-01-01
                                        • 1970-01-01
                                        • 1970-01-01
                                        • 1970-01-01
                                        • 1970-01-01
                                        • 1970-01-01
                                        相关资源
                                        最近更新 更多