UIButton에서 텍스트 밑줄


143

누구나 UIButton의 제목에 밑줄을 긋는 방법을 제안 할 수 있습니까? 사용자 정의 유형의 UIButton이 있고 제목에 밑줄을 표시하고 싶지만 인터페이스 빌더는 옵션을 제공하지 않습니다.

버튼의 글꼴 옵션을 선택할 때 인터페이스 빌더에서 없음, 단일, 이중, 색상을 선택하는 옵션을 제공하지만 버튼의 제목에 대한 변경 사항은 없습니다.

도움을 주셔서 감사합니다.


1
이 질문에서와 같이 UITextView를 속성 문자열에 링크를 추가하여 사용할 수 있습니다. stackoverflow.com/questions/21629784/…
Khaled 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
어쩌면 당신이 필요로하지 않았을 수도 있습니다!
Nick 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

밑줄에 인터페이스 빌더를 사용하려면 다음을 수행해야합니다.

  • 소중한 것으로 변경
  • 속성 관리자에서 텍스트를 강조 표시합니다
  • 마우스 오른쪽 버튼을 클릭하고 글꼴을 선택한 다음 밑줄을 선택하십시오.

IB를 사용한 밑줄

다른 사람이 만든 동영상 https://www.youtube.com/watch?v=5-ZnV3jQd9I


2
좋은 질문 @ new2ios 다른 사람이 알고있을 것입니다.
finneycanhelp

1
@finneycanhelp라는 새로운 질문을하겠습니다. Xcode 6.3에는 더 쉬운 방법이 있기를 바랍니다. 나는 당신의 솔루션을 설정하고 setTitle텍스트 로 사용할 수 있다는 것을 의미 합니다. 저에게 밑줄을 그리는 커스텀 버튼을 만드는 것은 다소 이국적입니다 (하나의 앱이 완성 되어도 iOS에 익숙하지 않을 수도 있습니다).
new2ios

2
finneydonehelped! 이거 고마워! 글꼴 팝업 대화 상자가 효과가없는 이유를 알 수 없습니다. 마우스 오른쪽 버튼 클릭이 완벽합니다.
IMFletcher 2016

2
Code에서 수행 할 때 약간의 작업을하는 이런 종류의 간단한 작업에 대해 Interface Builder 사용자에게 좋은 대답입니다. 감사! (Y)
Randika Vishman

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
이 방법을 사용하는 경우
중요한

2
굉장히, 그리고 색상에 대한 머리 위로 @daveMac 감사합니다. NSForegroundColorAttributeName
Ryan Crews

이 방법에서 버튼 밑줄은 텍스트에 가깝습니다. 밑줄의 y 위치를 변경하는 방법은 무엇입니까?
Ilesh P

49

인터페이스 빌더 자체에서이를 수행 할 수 있습니다.

  1. 속성 관리자를 선택하십시오
  2. 제목 유형을 일반에서 속성으로 변경

여기에 이미지 설명을 입력하십시오

  1. 적절한 글꼴 크기 및 텍스트 정렬 설정

여기에 이미지 설명을 입력하십시오

  1. 그런 다음 제목 텍스트를 선택하고 밑줄이 그어진 글꼴을 설정하십시오

여기에 이미지 설명을 입력하십시오


28

기여 문자열로 매우 간단합니다.

설정된 속성으로 사전을 작성하고 속성이 지정된 문자열에 적용하십시오. 그런 다음 uibutton에서 타당한 문자열을 uilabel의 attibutedtitle 또는 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

Nick의 대답은이 작업을 수행하는 훌륭하고 빠른 방법입니다.

drawRect그림자 에 대한 지원을 추가했습니다 .

버튼 제목에 텍스트 아래에 그림자가 있으면 Nick의 답변이 고려되지 않습니다.

여기에 이미지 설명을 입력하십시오

그러나 그림자의 높이만큼 밑줄을 아래로 이동할 수 있습니다.

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

그러면 다음과 같은 것을 얻을 수 있습니다 :

여기에 이미지 설명을 입력하십시오


self.titleLabel.font.descender; 이것은 아이폰 OS 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; 

경계가 변경되면 버튼이 다시 그려집니다.

둘째, 원래 코드는 버튼에 한 줄의 텍스트 만 있고 (내 버튼은 회전 할 때 두 줄로 줄 바꿈) 밑줄은 텍스트의 마지막 줄에만 나타납니다. 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

Xcode 10.3에서 2019 년 9 월 현재 작동하는 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()를 걸어 해당 제목에 밑줄을 표시하십시오.


1
iOS 10.3.1 이전 버전에서 작동하는지 확인할 수 있습니다 .Xcode 10.3은 내가 아는 한 Mojave보다 오래된 시뮬레이터를 지원하지 않습니다.
Max Desiatov

2

밑줄이 그어진 버튼을 계속 누르고 있으면 어떻게 처리 할 수 ​​있습니까? 이 경우 버튼의 텍스트 색상은 강조 표시된 색상에 따라 변경되지만 선은 원래 색상으로 유지됩니다. 정상 상태의 버튼 텍스트 색상이 검은 색이면 밑줄에도 검은 색이 표시됩니다. 버튼의 강조된 색상은 흰색입니다. 버튼을 계속 누르고 있으면 버튼 텍스트 색상이 검은 색에서 흰색으로 변경되지만 밑줄 색상은 검은 색으로 유지됩니다.


2
버튼이 강조 표시되고 선택되었는지 테스트하고 그에 따라 색상을 설정할 수 있습니다. 다시 그리기가 자동으로 요청되는지 확실하지 않으면 setSelected / setHighlighted를 재정의하고 super 및 [self setNeedsDisplay]를 호출해야합니다.
Nick H247

2

XCode의 글꼴 편집기에 버그가 있다고 생각합니다. 인터페이스 빌더를 사용하는 경우 제목을 일반에서 속성으로 변경해야하는 경우, 텍스트 편집기를 열고 밑줄이있는 텍스트를 작성하고 XCode의 텍스트 상자에 복사하여 붙여 넣기


2

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

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

사용자 정의 밑줄 색상, 선폭 및 간격이있는 @ NickH247의 답변에 대한 스위프트 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")
    }
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.