Підкреслення тексту в UIButton


143

Хтось може підказати, як підкреслити назву UIButton? У мене є тип UIB на замовлення, і я хочу, щоб заголовок був підкреслений, але Інтерфейс не створює жодних варіантів для цього.

У програмі Interface Builder, коли ви вибираєте опцію шрифту для кнопки, вона надає можливість вибрати None, Single, Double, Color, але жодна з них не вносить жодних змін до заголовка на кнопці.

Будь-яка допомога вдячна.


1
Ви можете використовувати UITextView з приписується рядок , додавши посилання на нього , як в цьому питанні stackoverflow.com/questions/21629784 / ...
Халед Annajar

Відповіді:


79

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

1
можливо, не так своєчасно, як вам потрібно!
Нік H247

4
Дякую, я зателефонував так: UIButton * btn = [UIUnderlinedButton buttonWithType: UIButtonTypeCustom];
hb922

2
Код працює добре, але я помітив, що підкреслення не зменшується / зростає, коли подання змінює розмір при обертанні, викликане тим, що drawRectне викликається обертанням. Це можна вирішити, встановивши кнопку так, щоб вона перемальовувалася так: myButton.contentMode = UIViewContentModeRedraw;яка змушує кнопку перемальовуватись, коли змінюються межі.
AndroidNoob

4
Ви також можете змінити такий setTitleспосіб, як:objective-c - (void)setTitle:(NSString *)title forState:(UIControlState)state { [super setTitle:title forState:state]; [self setNeedsDisplay]; }
Kirualex

379

Щоб використати конструктор інтерфейсів для підкреслення, потрібно:

  • Змініть його на атрибутивне
  • Виділіть текст у інспекторі атрибутів
  • Клацніть правою кнопкою миші, виберіть шрифт, а потім підкреслити

Підкресліть за допомогою ІБ

Відео, який хтось інший зробив https://www.youtube.com/watch?v=5-ZnV3jQd9I


2
Добре запитання @ new2ios Можливо, хтось ще знає
finneycanhelp

1
Я поставлю нове запитання, @finneycanhelp. Я сподіваюся, що в Xcode 6.3 буде більш простий спосіб. Я маю на увазі, що, можливо, я можу встановити ваше рішення, а потім використовувати setTitleз атрибутивним текстом. Для мене створення спеціальної кнопки для малювання підкреслює трохи екзотично (можливо, я все ще новачок в iOS, навіть якщо один додаток виконано).
new2ios

2
finneydonehelped! спасибі за це! не вдалося зрозуміти, чому діалогове вікно "Шрифти" не впливало. Клацніть правою кнопкою миші ідеально.
IMFletcher

2
Хороша відповідь користувачам Interface Builder за такі прості речі, які мало працюють під час роботи в Code. Дякую! (Y)
Рандіка Вішман

1
Чому розробники iOS вважають за краще писати дуже довгий код саме для дуже простого питання?
mr5

129

Від 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];

9
Просто майте на увазі, що коли ви робите це таким чином, ви також повинні додати атрибут для кольору, оскільки текст, який приписаний, не буде використовувати колір, який ви встановили за допомогою setTitleColor: forState:
daveMac

2
Дивовижно, і дякую @daveMac за голову над кольором. Для тих, хто не знає атрибуту, це: NSForegroundColorAttributeName
Ryan Crews

у цьому методі підкреслення кнопки близьке до тексту будь-якого методу для зміни положення y підкреслення?
Ілеш П

49

Ви можете це зробити в самому конструкторі інтерфейсів.

  1. Виберіть інспектор атрибутів
  2. Змініть тип заголовка від звичайного до атрибутивного

введіть тут опис зображення

  1. Встановіть відповідний розмір шрифту та вирівнювання тексту

введіть тут опис зображення

  1. Потім виберіть текст заголовка і встановіть шрифт як підкреслений

введіть тут опис зображення


28

Це дуже просто з атрибутивним рядком

Створюється словник із заданими атрибутами та застосовується до атрибутованого рядка. Тоді ви можете встановити атрибутивну рядок як attibutedtitle в uibutton або attributedtekst в 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];

Що commentString; ви копіювали з відповіді @ NickH247?
значення-питання

21

Ось моя функція, працює в 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)
    }
}

13

Відповідь Ніка - це чудовий, швидкий спосіб зробити це.

Я додав підтримку 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
KING

5

Для 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)
    }
}

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

3

Розширюючи відповідь на @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);

}


}

Сподіваюся, цей код допомагає комусь іншому!


3

Швидко

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

3

За допомогою цього коду можна додати підкреслення з пробілом у кнопці.

  • Коли я спробував намалювати підкреслювач у програмі для створення інтерфейсів. Це виглядає як на зображенні нижче.

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

Дякуємо за цей фрагмент коду, який може надати деяку обмежену та негайну допомогу. Правильне пояснення значно покращило б його довгострокове значення, показавши, чому це хороше рішення проблеми, та зробило б кориснішим майбутнім читачам інші подібні питання. Будь ласка, відредагуйте свою відповідь, щоб додати пояснення, включаючи зроблені вами припущення.
Toby Speight

3

Версія Swift 5.0, яка працює з вересня 2019 року в Xcode 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()щоб цей заголовок підкреслити.


1
Я можу підтвердити, що це працює на версіях, старих як iOS 10.3.1, наскільки я знаю, Xcode 10.3 не підтримує тренажери, старіші, ніж у Mojave.
Макс

2

Як вирішуватиметься випадок, коли ми тримаємо кнопку підкресленою? У такому випадку кольоровість тексту кнопки змінюється відповідно до виділеного кольору, але лінія залишається оригінальним кольором. Скажімо, якщо колір тексту кнопки у звичайному стані - чорний, то його підкреслення також матиме чорний колір. Колір виділеного кнопки - білий. Утримуючи натиснутою кнопку, змінюється колір тексту кнопки з чорного на білий, але колір підкреслення залишається чорним.


2
Ви можете перевірити, чи кнопка підсвічена та чи вибрана, і встановити колір відповідно. не впевнений, чи буде запрошено перемальовку автоматично, якщо ні, то вам потрібно буде переосмислити setSelected / setHighlight та зателефонувати super і [self setNeedsDisplay]
Nick H247

2

Я вважаю, що це помилка в редакторі шрифтів у XCode. Якщо ви використовуєте конструктор інтерфейсів, вам потрібно змінити заголовок з Plain на Attributed, відкрийте TextEdit, щоб створити підкреслений текст і скопіювати вставити в текстове поле в XCode


2

Відповідь Ніка 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);
    }
}

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

1

Версія 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")
    }
}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.