UIButton 中的下划线文本

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

在 Interface Builder 选择“按钮的字体选项”时,它提供了“无”、“单”、“双”、“颜色”选项,但是这些选项都没有对“按钮上的标题”进行任何更改。

感谢你的帮助。

103025 次浏览

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

尼克的回答是一个很好的,快速的方法来做到这一点。

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

尼克的回答没有考虑到你的按钮标题在文本下方有阴影:

enter image description here

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

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

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

enter image description here

如何处理案件,当我们保持按下划线按钮?在这种情况下,按钮的文本颜色根据突出显示的颜色变化,但线仍然是原来的颜色。例如,如果按钮文本颜色在正常状态是黑色,那么它的下划线也将有黑色。按钮突出显示的颜色是白色。保持按钮按下改变按钮文本颜色从黑色到白色,但下划线颜色仍然是黑色。

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

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

对于@Nick H247给出的答案,我遇到了一个问题: 首先,当按钮旋转时下划线没有重新绘制; 这可以通过设置按钮重新绘制来解决:

myButton.contentMode = UIViewContentModeRedraw;

这将强制按钮在边界更改时重新绘制。

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

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


}




}

希望这个代码能帮到别人!

使用属性化字符串非常简单

创建具有设置属性的字典并应用于属性化字符串。然后,可以在 uilabel 中将属性化字符串设置为 Attibutedtitle 或 Atbutedtext。

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,你必须将标题从“普通”改为“属性”,打开“文本编辑”,创建带下划线的文本,并在 XCode 中复制粘贴到文本框

要用 Interface Builder 来划线,你必须:

  • 把它改成属性
  • 突出显示“属性”检查器中的文本
  • 右键单击,选择“字体”,然后选择“下划线”

Underline using IB

别人拍的视频 Https://www.youtube.com/watch?v=5-znv3jqd9i

迅速

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

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

快速3版 @ NickH247’s答案与自定义下划线颜色,线宽和间隙:

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

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

  • 当我试图从 Interface Builder 中画一条下划线时,它看起来像下图。

1 Interface Builder 参考

enter image description here

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

2-使用描述的代码

enter image description here

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

你可以在 Interface Builder 里做。

  1. 选择属性检查器
  2. 将 title 类型从纯文本更改为属性化

enter image description here

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

enter image description here

  1. 然后选择标题文本并将字体设置为带下划线

enter image description here

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

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()使标题带下划线。