Underlining text in UIButton

后端 未结 18 1812
终归单人心
终归单人心 2020-11-29 15:56

Can anyone suggest how to underline the title of a UIButton ? I have a UIButton of Custom type, and I want the Title to be underlined, but the Interface Builder does not pr

相关标签:
18条回答
  • 2020-11-29 16:16
    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)
        }
    
    0 讨论(0)
  • 2020-11-29 16:17

    You can do it in the interface builder itself.

    1. Select the attribute inspector
    2. Change the title type from plain to attributed

    1. Set appropriate font size and text alignment

    1. Then select the title text and set the font as underlined

    0 讨论(0)
  • 2020-11-29 16:17

    Here is my function, works in 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)
    }
    

    UPDATE Swift 3.0 extension:

    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)
        }
    }
    
    0 讨论(0)
  • 2020-11-29 16:17

    Swift 3 version for @NickH247's answer with custom underline color, linewidth and gap:

    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")
        }
    }
    
    0 讨论(0)
  • 2020-11-29 16:18

    Expanding on the answer by @Nick H247, I experienced an issue where firstly the underline was not redrawing when the button resized on rotation; this can be solved by setting your button to redraw like so:

    myButton.contentMode = UIViewContentModeRedraw; 
    

    This forces the button to redraw when the bounds change.

    Secondly, the original code assumed you only had 1 line of text in the button (my button wraps to 2 lines on rotation) and the underline only appears on the last line of text. The drawRect code can be modified to first calculate the number of lines in the button, then put an underline on every line rather than just the bottom, like so:

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

    Hope this code helps someone else!

    0 讨论(0)
  • 2020-11-29 16:18

    How will one handle the case when we keep a button underlined pressed? In that case the button's textcolor changes according to highlighted color but line remains of original color. Let say if button text color in normal state is black then its underline will also have black color. The button's highlighted color is white. Keeping button pressed changes button text color from black to white but underline color remains black.

    0 讨论(0)
提交回复
热议问题