【问题标题】:Underlining text in UIButtonUIButton 中的文本下划线
【发布时间】:2011-02-07 11:17:08
【问题描述】:

谁能建议如何在 UIButton 的标题下划线?我有一个自定义类型的 UIButton,我希望标题带有下划线,但 Interface Builder 没有提供任何选项。

在 Interface Builder 中,当您为按钮选择字体选项时,它提供了选择无、单、双、颜色的选项,但这些选项都不会对按钮上的标题进行任何更改。

任何帮助表示赞赏。

【问题讨论】:

标签: text formatting uibutton


【解决方案1】:

要使用界面生成器来下划线,必须:

  • 将其更改为属性
  • 在属性检查器中突出显示文本
  • 右键单击,选择字体,然后选择下划线

别人制作的视频 https://www.youtube.com/watch?v=5-ZnV3jQd9I

【讨论】:

  • 好问题@new2ios 也许别人知道
  • 我会问新问题,@finneycanhelp。我希望在 Xcode 6.3 中会有更简单的方法。我的意思是我可以设置您的解决方案,然后将setTitle 与属性文本一起使用。对我来说,创建自定义按钮来绘制下划线有点异国情调(即使完成了一个应用程序,我可能还是 iOS 新手)。
  • finneydone 帮了忙!谢谢你!无法弄清楚为什么字体弹出对话框没有效果。右键是完美的。
  • Interface Builder 用户对这类简单的事情的好答案,在代码中做这些事情很少。谢谢! (Y)
  • 为什么 iOS 开发者更喜欢为一个非常简单的问题编写很长的代码?
【解决方案2】:

从 iOS6 开始,现在可以使用 NSAttributedString 以更灵活的方式执行下划线(以及任何其他属性字符串支持):

NSMutableAttributedString *commentString = [[NSMutableAttributedString alloc] initWithString:@"The Quick Brown Fox"];

[commentString addAttribute:NSUnderlineStyleAttributeName value:[NSNumber numberWithInteger:NSUnderlineStyleSingle] range:NSMakeRange(0, [commentString length])];

[button setAttributedTitle:commentString forState:UIControlStateNormal];

注意:将此作为另一个答案添加 - 因为它与我之前的答案完全不同。

编辑: 奇怪的是(至少在 iOS8 中)你必须在第一个字符下划线,否则它不起作用!

作为一种解决方法,将第一个字符设置为清晰的颜色下划线!

    // underline Terms and condidtions
    NSMutableAttributedString* tncString = [[NSMutableAttributedString alloc] initWithString:@"View Terms and Conditions"];

    // workaround for bug in UIButton - first char needs to be underlined for some reason!
    [tncString addAttribute:NSUnderlineStyleAttributeName
                      value:@(NSUnderlineStyleSingle)
                      range:(NSRange){0,1}];
    [tncString addAttribute:NSUnderlineColorAttributeName value:[UIColor clearColor] range:NSMakeRange(0, 1)];


    [tncString addAttribute:NSUnderlineStyleAttributeName
                      value:@(NSUnderlineStyleSingle)
                      range:(NSRange){5,[tncString length] - 5}];

    [tncBtn setAttributedTitle:tncString forState:UIControlStateNormal];

【讨论】:

  • 请注意,当您这样做时,您还必须为颜色添加属性,因为属性标题文本不会使用您使用 setTitleColor:forState: 设置的颜色:
  • 太棒了,感谢@daveMac 对颜色的提醒。对于那些不知道它的属性的人:NSForegroundColorAttributeName
  • 在这个方法中按钮下划线接近文本有什么方法可以改变下划线的y位置吗?
【解决方案3】:

UIUnderlinedButton.h

@interface UIUnderlinedButton : UIButton {

}


+ (UIUnderlinedButton*) underlinedButton;
@end

UIUnderlinedButton.m

@implementation UIUnderlinedButton

+ (UIUnderlinedButton*) underlinedButton {
    UIUnderlinedButton* button = [[UIUnderlinedButton alloc] init];
    return [button autorelease];
}

- (void) drawRect:(CGRect)rect {
    CGRect textRect = self.titleLabel.frame;

    // need to put the line at top of descenders (negative value)
    CGFloat descender = self.titleLabel.font.descender;

    CGContextRef contextRef = UIGraphicsGetCurrentContext();

    // set to same colour as text
    CGContextSetStrokeColorWithColor(contextRef, self.titleLabel.textColor.CGColor);

    CGContextMoveToPoint(contextRef, textRect.origin.x, textRect.origin.y + textRect.size.height + descender);

    CGContextAddLineToPoint(contextRef, textRect.origin.x + textRect.size.width, textRect.origin.y + textRect.size.height + descender);

    CGContextClosePath(contextRef);

    CGContextDrawPath(contextRef, kCGPathStroke);
}


@end

【讨论】:

  • 可能没有你需要的那么及时!
  • 谢谢,我最终这样称呼它: UIButton *btn = [UIUnderlinedButton buttonWithType:UIButtonTypeCustom];
  • 代码运行良好,但我注意到当视图在旋转时改变大小时,下划线没有缩小/增长,这是由于 drawRect 没有在旋转时被调用。这可以通过将您的按钮设置为重绘来解决,如下所示:myButton.contentMode = UIViewContentModeRedraw; 当边界改变时强制按钮重绘。
  • 您也可以像这样覆盖setTitle 方法:objective-c - (void)setTitle:(NSString *)title forState:(UIControlState)state { [super setTitle:title forState:state]; [self setNeedsDisplay]; }
【解决方案4】:

您可以在界面生成器本身中完成。

  1. 选择属性检查器
  2. 将标题类型从普通更改为属性

  1. 设置适当的字体大小和文本对齐方式

  1. 然后选择标题文字,设置字体为下划线

【讨论】:

    【解决方案5】:

    属性字符串很简单

    创建具有设置属性的字典并应用于属性字符串。然后你可以在uibutton中将属性字符串设置为attibutedtitle或uilabel中的attributetext。

    NSDictionary *attrDict = @{NSFontAttributeName : [UIFont
     systemFontOfSize:14.0],NSForegroundColorAttributeName : [UIColor
     whiteColor]};
     NSMutableAttributedString *title =[[NSMutableAttributedString alloc] initWithString:@"mybutton" attributes: attrDict]; 
    [title addAttribute:NSUnderlineStyleAttributeName value:[NSNumber numberWithInteger:NSUnderlineStyleSingle] range:NSMakeRange(0,[commentString length])]; [btnRegLater setAttributedTitle:title forState:UIControlStateNormal];
    

    【讨论】:

    • commentString 是什么;你是从@NickH247 的回答中复制过来的吗?
    【解决方案6】:

    这是我的函数,适用于 Swift 1.2。

    func underlineButton(button : UIButton, text: String) {
    
        var titleString : NSMutableAttributedString = NSMutableAttributedString(string: text)
        titleString.addAttribute(NSUnderlineStyleAttributeName, value: NSUnderlineStyle.StyleSingle.rawValue, range: NSMakeRange(0, count(text.utf8)))
        button.setAttributedTitle(titleString, forState: .Normal)
    }
    

    更新 Swift 3.0 扩展:

    extension UIButton {
        func underlineButton(text: String) {
            let titleString = NSMutableAttributedString(string: text)
            titleString.addAttribute(NSUnderlineStyleAttributeName, value: NSUnderlineStyle.styleSingle.rawValue, range: NSMakeRange(0, text.characters.count))
            self.setAttributedTitle(titleString, for: .normal)
        }
    }
    

    【讨论】:

      【解决方案7】:

      Nick 的回答是一个很好、快速的方法。

      我在 drawRect 中添加了对阴影的支持。

      如果您的按钮标题在文本下方有阴影,则尼克的回答没有考虑到:

      但是您可以像这样将下划线向下移动阴影的高度:

      CGFloat descender = self.titleLabel.font.descender;
      CGContextRef contextRef = UIGraphicsGetCurrentContext();
      CGFloat shadowHeight = self.titleLabel.shadowOffset.height;
      descender += shadowHeight;
      

      然后你会得到这样的东西:

      【讨论】:

      • self.titleLabel.font.descender;这在 iOS 3.0 中已被贬值
      【解决方案8】:

      截至 2019 年 9 月在 Xcode 10.3 中运行的 Swift 5.0 版本:

      extension UIButton {
        func underlineText() {
          guard let title = title(for: .normal) else { return }
      
          let titleString = NSMutableAttributedString(string: title)
          titleString.addAttribute(
            .underlineStyle,
            value: NSUnderlineStyle.single.rawValue,
            range: NSRange(location: 0, length: title.count)
          )
          setAttributedTitle(titleString, for: .normal)
        }
      }
      

      要使用它,首先使用button.setTitle("Button Title", for: .normal) 设置您的按钮标题,然后调用button.underlineText() 使该标题加下划线。

      【讨论】:

      • 据我所知,我可以确认这适用于 iOS 10.3.1 之前的版本,Xcode 10.3 不支持早于 Mojave 的模拟器。
      【解决方案9】:

      对于 Swift 3,可以使用以下扩展:

      extension UIButton {
          func underlineButton(text: String) {
              let titleString = NSMutableAttributedString(string: text)
              titleString.addAttribute(NSUnderlineStyleAttributeName, value: NSUnderlineStyle.styleSingle.rawValue, range: NSMakeRange(0, text.characters.count))
              self.setAttributedTitle(titleString, for: .normal)
          }
      }
      

      【讨论】:

        【解决方案10】:
        // Only override drawRect: if you perform custom drawing.
        // An empty implementation adversely affects performance during animation.
        - (void)drawRect:(CGRect)rect {
        CGRect textRect = self.titleLabel.frame;
        
        // need to put the line at top of descenders (negative value)
        CGFloat descender = self.titleLabel.font.descender;
        
        CGContextRef contextRef = UIGraphicsGetCurrentContext();
        UIColor *colr;
        // set to same colour as text
        if (self.isHighlighted || self.isSelected) {
            colr=self.titleLabel.highlightedTextColor;
        }
        else{
            colr= self.titleLabel.textColor;
        }
        CGContextSetStrokeColorWithColor(contextRef, colr.CGColor);
        
        CGContextMoveToPoint(contextRef, textRect.origin.x, textRect.origin.y +        textRect.size.height + descender);
        
        CGContextAddLineToPoint(contextRef, textRect.origin.x + textRect.size.width, textRect.origin.y + textRect.size.height + descender);
        
        CGContextClosePath(contextRef);
        
        CGContextDrawPath(contextRef, kCGPathStroke);
        }
        //Override this to change the underline color to highlighted color
        -(void)setHighlighted:(BOOL)highlighted
        {
        [super setHighlighted:highlighted];
        // [self setNeedsDisplay];
        }
        

        【讨论】:

          【解决方案11】:

          扩展@Nick H247 的答案,我遇到了一个问题,首先当按钮在旋转时调整大小时下划线没有重绘;这可以通过将按钮设置为像这样重绘来解决:

          myButton.contentMode = UIViewContentModeRedraw; 
          

          当边界改变时,这会强制按钮重绘。

          其次,原始代码假设您在按钮中只有 1 行文本(我的按钮在旋转时换行为 2 行),并且下划线仅出现在文本的最后一行。可以修改 drawRect 代码,首先计算按钮中的行数,然后在每一行而不是底部添加下划线,如下所示:

           - (void) drawRect:(CGRect)rect {
          CGRect textRect = self.titleLabel.frame;
          
          // need to put the line at top of descenders (negative value)
          CGFloat descender = self.titleLabel.font.descender;
          
          CGContextRef contextRef = UIGraphicsGetCurrentContext();
          
          // set to same colour as text
          CGContextSetStrokeColorWithColor(contextRef, self.titleLabel.textColor.CGColor);
          
          CGSize labelSize = [self.titleLabel.text sizeWithFont:self.titleLabel.font
                                      constrainedToSize:self.titleLabel.frame.size
                                          lineBreakMode:UILineBreakModeWordWrap];
          
          CGSize labelSizeNoWrap = [self.titleLabel.text sizeWithFont:self.titleLabel.font forWidth:self.titleLabel.frame.size.width lineBreakMode:UILineBreakModeMiddleTruncation ];
          
          int numberOfLines = abs(labelSize.height/labelSizeNoWrap.height);
          
          for(int i = 1; i<=numberOfLines;i++) {
           //        Original code
           //        CGContextMoveToPoint(contextRef, textRect.origin.x, textRect.origin.y + textRect.size.height + descender + PADDING);
           //        
           //        CGContextAddLineToPoint(contextRef, textRect.origin.x + textRect.size.width, textRect.origin.y + textRect.size.height + descender);
          
              CGContextMoveToPoint(contextRef, textRect.origin.x, textRect.origin.y + (labelSizeNoWrap.height*i) + descender + PADDING);
          
              CGContextAddLineToPoint(contextRef, textRect.origin.x + textRect.size.width, textRect.origin.y + (labelSizeNoWrap.height*i) + descender);
          
              CGContextClosePath(contextRef);
          
              CGContextDrawPath(contextRef, kCGPathStroke);
          
          }
          
          
          }
          

          希望此代码对其他人有所帮助!

          【讨论】:

            【解决方案12】:

            迅速

            func underlineButton(button : UIButton) {
            
            var titleString : NSMutableAttributedString = NSMutableAttributedString(string: button.titleLabel!.text!)
            titleString.addAttribute(NSUnderlineStyleAttributeName, value: NSUnderlineStyle.StyleSingle.rawValue, range: NSMakeRange(0, button.titleLabel!.text!.utf16Count))
            button.setAttributedTitle(titleString, forState: .Normal)}
            

            【讨论】:

              【解决方案13】:

              您可以使用此代码在按钮中添加带间距的下划线。

              • 当我尝试从界面生成器中绘制下划线时。如下图所示。

              1 - 界面构建器参考

              • 使用下面的代码后,我得到了我想要的结果。

              2 - 使用描述的代码

              public func setTextUnderline()
                  {
                      let dummyButton: UIButton = UIButton.init()
                      dummyButton.setTitle(self.titleLabel?.text, for: .normal)
                      dummyButton.titleLabel?.font = self.titleLabel?.font
                      dummyButton.sizeToFit()
              
                      let dummyHeight = dummyButton.frame.size.height + 3
              
                      let bottomLine = CALayer()
                      bottomLine.frame = CGRect.init(x: (self.frame.size.width - dummyButton.frame.size.width)/2, y: -(self.frame.size.height - dummyHeight), width: dummyButton.frame.size.width, height: 1.0)
                      bottomLine.backgroundColor = self.titleLabel?.textColor.cgColor
                      self.layer.addSublayer(bottomLine)
                  }
              

              【讨论】:

              • 感谢您提供此代码 sn-p,它可能会提供一些有限的即时帮助。一个正确的解释would greatly improve 它的长期价值通过展示为什么这是一个很好的解决问题的方法,并将使它对未来有其他类似问题的读者更有用。请edit您的回答添加一些解释,包括您所做的假设。
              【解决方案14】:

              当我们按住一个带下划线的按​​钮时,将如何处理这种情况?在这种情况下,按钮的文本颜色会根据突出显示的颜色而变化,但线条保持原始颜色。假设如果正常状态下的按钮文本颜色为黑色,则其下划线也将具有黑色。该按钮的突出显示颜色为白色。按住按钮会将按钮文本颜色从黑色更改为白色,但下划线颜色仍为黑色。

              【讨论】:

              • 您可以测试按钮是否突出显示或被选中,并相应地设置颜色。不确定是否会自动请求重绘,如果不是,您需要覆盖 setSelected/setHighlighted 并调用 super 和 [self setNeedsDisplay]
              【解决方案15】:

              我相信这是 XCode 字体编辑器中的一些错误。如果您使用界面生成器,则必须将标题从普通更改为属性,打开 TextEdit 创建带下划线的文本并复制粘贴到 XCode 中的文本框

              【讨论】:

                【解决方案16】:

                Nick H247 的回答,但 Swift 方法:

                import UIKit
                
                class UnderlineUIButton: UIButton {
                
                    override func drawRect(rect: CGRect) {
                        super.drawRect(rect)
                
                        let textRect = self.titleLabel!.frame
                
                        var descender = self.titleLabel?.font.descender
                
                        var contextRef: CGContextRef = UIGraphicsGetCurrentContext();
                
                        CGContextSetStrokeColorWithColor(contextRef, self.titleLabel?.textColor.CGColor);
                
                        CGContextMoveToPoint(contextRef, textRect.origin.x, textRect.origin.y + textRect.size.height + descender!);
                
                        CGContextAddLineToPoint(contextRef, textRect.origin.x + textRect.size.width, textRect.origin.y + textRect.size.height + descender!);
                
                        CGContextClosePath(contextRef);
                
                        CGContextDrawPath(contextRef, kCGPathStroke);
                    }
                }
                

                【讨论】:

                  【解决方案17】:
                  func underline(text: String, state: UIControlState = .normal, color:UIColor? = nil) {
                          var titleString = NSMutableAttributedString(string: text)
                  
                          if let color = color {
                              titleString = NSMutableAttributedString(string: text,
                                                 attributes: [NSForegroundColorAttributeName: color])
                          }
                  
                          let stringRange = NSMakeRange(0, text.characters.count)
                          titleString.addAttribute(NSUnderlineStyleAttributeName,
                                                   value: NSUnderlineStyle.styleSingle.rawValue,
                                                   range: stringRange)
                  
                          self.setAttributedTitle(titleString, for: state)
                      }
                  

                  【讨论】:

                    【解决方案18】:

                    @NickH247's 的 Swift 3 版本带有自定义下划线颜色、线宽和间隙:

                    import Foundation
                    
                    class UnderlinedButton: UIButton {
                    
                        private let underlineColor: UIColor
                        private let thickness: CGFloat
                        private let gap: CGFloat
                    
                        init(underlineColor: UIColor, thickness: CGFloat, gap: CGFloat, frame: CGRect? = nil) {
                            self.underlineColor = underlineColor
                            self.thickness = thickness
                            self.gap = gap
                            super.init(frame: frame ?? .zero)
                        }
                    
                        override func draw(_ rect: CGRect) {
                            super.draw(rect)
                    
                            guard let textRect = titleLabel?.frame,
                                let decender = titleLabel?.font.descender,
                                let context = UIGraphicsGetCurrentContext() else { return }
                    
                            context.setStrokeColor(underlineColor.cgColor)
                            context.move(to: CGPoint(x: textRect.origin.x, y: textRect.origin.y + textRect.height + decender + gap))
                            context.setLineWidth(thickness)
                            context.addLine(to: CGPoint(x: textRect.origin.x + textRect.width, y: textRect.origin.y + textRect.height + decender + gap))
                            context.closePath()
                            context.drawPath(using: .stroke)
                        }
                    
                        required init?(coder aDecoder: NSCoder) {
                            fatalError("init(coder:) has not been implemented")
                        }
                    }
                    

                    【讨论】:

                      猜你喜欢
                      • 1970-01-01
                      • 2013-08-22
                      • 1970-01-01
                      • 1970-01-01
                      • 2012-10-18
                      • 2010-10-28
                      • 1970-01-01
                      • 1970-01-01
                      • 2014-03-22
                      相关资源
                      最近更新 更多