Text 在UIButton中给文本加下划线

Text 在UIButton中给文本加下划线,text,formatting,uibutton,Text,Formatting,Uibutton,有人能建议如何在UIButton的标题下加下划线吗?我有一个自定义类型的UIButton,我希望标题加下划线,但界面生成器不提供任何选项 在Interface Builder中,当您为按钮选择字体选项时,它提供了选择无、单色、双色的选项,但这些选项都不会对按钮上的标题进行任何更改 感谢您的帮助。ui下划线按钮.h @interface UIUnderlinedButton : UIButton { } + (UIUnderlinedButton*) underlinedButton; @e

有人能建议如何在UIButton的标题下加下划线吗?我有一个自定义类型的UIButton,我希望标题加下划线,但界面生成器不提供任何选项

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

感谢您的帮助。

ui下划线按钮.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

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

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

如果您的按钮标题在文本下方有阴影,Nick的回答将不予考虑:

但您可以按阴影的高度向下移动下划线,如下所示:

CGFloat descender = self.titleLabel.font.descender;
CGContextRef contextRef = UIGraphicsGetCurrentContext();
CGFloat shadowHeight = self.titleLabel.shadowOffset.height;
descender += shadowHeight;
然后你会得到这样的结果:


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

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

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

在@Nick H247的回答的基础上,我遇到了一个问题:首先,当按钮旋转调整大小时,下划线没有重新绘制;这可以通过如下方式将按钮设置为重画来解决:

myButton.contentMode = UIViewContentModeRedraw; 
这将在边界更改时强制按钮重新绘制

其次,原始代码假设按钮中只有一行文本(我的按钮旋转时换行为两行),下划线只出现在最后一行文本上。可以修改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);

}


}
-(void)drawRect:(CGRect)rect{
CGRect textRect=self.titleLabel.frame;
//需要将线置于下降器顶部(负值)

CGFloat-downer=self.titleLabel.font.downer; CGContextRef contextRef=UIGraphicsGetCurrentContext(); //设置为与文本相同的颜色 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 for width:self.titleLabel.frame.size.width lineBreakMode:UILineBreakModeMiddleTruncation]; int numberOfLines=abs(labelSize.height/labelSizeNoWrap.height);
对于(inti=1;i而言,使用属性字符串非常简单

创建具有设置属性的词典并应用于属性字符串。然后,您可以在uibutton中将属性字符串设置为AttibuteTitle,或在uilabel中将属性文本设置为AttibuteText

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

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

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

别人制作的视频 在swift中

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

Nick H247的回答,但快速的方法:

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

这是我的函数,在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)
    }
}

对于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)
    }
}
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")
    }
}

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

  • 当我试图从interface builder中绘制下划线时,它看起来像下图
1-界面生成器参考

  • 在使用了下面的代码之后,我得到了我想要的结果
2-使用描述的代码


您可以在界面生成器本身中执行此操作

  • 选择属性检查器
  • 将标题类型从普通更改为属性
  • 设置适当的字体大小和文本对齐方式
  • 然后选择标题文本并将字体设置为带下划线

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

    扩展按钮{
    func underlineText(){
    guard let title=title(用于:。正常)else{return}
    让titleString=nsmutableAttributeString(字符串:title)
    titleString.addAttribute(
    .内衣风格,
    值:NSUnderlineStyle.single.rawValue,
    范围:NSRange(位置:0,长度:title.count)
    )
    SetAttributeTitle(标题字符串,用于:。正常)
    }
    }
    

    要使用它,请先用
    button.setTitle(“button title”,用于:.normal)
    设置按钮标题,然后调用
    button.underlineText()
    使标题加下划线。

    可能没有您需要的那么及时!谢谢,我最后按如下方式调用它:UIButton*btn=[uiunderlineedbutton button button with type:uibuttonypecustom];代码运行良好,但我注意到,当视图在旋转时更改大小时,下划线没有缩小/增大,这是由于旋转时未调用
    drawRect
    造成的。可以通过将按钮设置为重画来解决此问题:
    myButton.contentMode=UIViewContentModeR
    
    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)
        }
    
    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)
        }