Подчеркивание текста в UIButton
может ли кто-нибудь предложить, как подчеркнуть название UIButton ? У меня есть UIButton пользовательского типа, и я хочу, чтобы заголовок был подчеркнут, но построитель интерфейса не предоставляет никаких возможностей для этого.
в Interface Builder при выборе опции шрифта для кнопки он предоставляет возможность выбрать None, Single, Double, Color, но ни один из них не предоставляет никаких изменений в заголовке кнопки.
любая помощь ценится.
17 ответов:
UIUnderlinedButton.h
@interface UIUnderlinedButton : UIButton { } + (UIUnderlinedButton*) underlinedButton; @endUIUnderlinedButton.м
@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
чтобы использовать interface builder для подчеркивания, нужно:
- измените его на attributed
- Выделите текст в инспекторе атрибутов
- щелкните правой кнопкой мыши, выберите шрифт, а затем подчеркните
видео кто-то сделал https://www.youtube.com/watch?v=5-ZnV3jQd9I
из 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];Примечание: добавлено это как еще один ответ-как его совершенно другое решение для моего предыдущего.
Edit: как ни странно (по крайней мере, в 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];
Это очень просто с приписанной строки
создает словарь с заданными атрибутами и применяется к приписанной строке. Затем вы можете установить приписанную строку как attibutedtitle в uibutton или attributedtext в uilabel.
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];
вот моя функция, работает в 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) } }
ответ Ника-отличный, быстрый способ сделать это.
я добавил поддержку
drawRectдля теней.ответ Ника не учитывает, если Название вашей кнопки имеет тень под текстом:
но вы можете переместить подчеркивание вниз по высоте тени следующим образом:
CGFloat descender = self.titleLabel.font.descender; CGContextRef contextRef = UIGraphicsGetCurrentContext(); CGFloat shadowHeight = self.titleLabel.shadowOffset.height; descender += shadowHeight;затем вы получите что-то вроде этого:
для 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) } }
// 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]; }
расширяя ответ @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); } }надеюсь этот код поможет кому-то еще!
Как будет обрабатывать случай, когда мы будем держать кнопку подчеркнуто нажатой? В этом случае цвет текста кнопки изменяется в соответствии с выделенным цветом, но линия остается исходного цвета. Допустим, если цвет текста кнопки в нормальном состоянии черный, то его подчеркивание также будет иметь черный цвет. Выделенный цвет кнопки-белый. Удержание нажатой кнопки изменяет цвет текста кнопки с черного на белый, но цвет подчеркивания остается черным.
Я считаю, что это какая-то ошибка в Редакторе шрифтов в XCode. Если вы используете interface builder, вам нужно изменить заголовок с простого на атрибутивный, открыть TextEdit создать подчеркнутый текст и скопировать-вставить в текстовое поле в XCode
быстро
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); } }
Вы можете использовать этот код, чтобы добавить подчеркивание с пробелами в кнопку.
- когда я попытался нарисовать подчеркивание из interface builder. Это выглядит как ниже изображения.
1-Ссылка на построитель интерфейса
- и после использования ниже кода я достиг результата, как я хотел.
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) }
Swift 3 версия для @NickH247 это ответ с пользовательским цветом подчеркивания, шириной линии и пробелом:
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) }






Comments