Underline covers text in NSAttributedString

徘徊边缘 提交于 2019-12-08 14:07:13

问题


I'm trying to create an attributed string but the underline covers my text instead of appearing behind it:

Is there a way to fix this? I'm using the following code:

let paragraphStyle = NSMutableParagraphStyle()
paragraphStyle.lineSpacing = 10.0

let attributes = [NSForegroundColorAttributeName: UIColor.white,
                  NSUnderlineStyleAttributeName: NSUnderlineStyle.styleThick.rawValue,
                  NSUnderlineColorAttributeName: UIColor.red,
                  NSParagraphStyleAttributeName: paragraphStyle]

let attributedString = NSAttributedString(string: "Story", attributes: attributes)

Thanks!

EDIT:

To give more context:

I'm displaying the attributed string on a UILabel placed in a .xib file:

view.textLabel.attributedText = attributedString

The label has the following font: System Bold 32.0

I'm running the code on iPhone 6 - iOS 10.3 simulator.

EDIT 2:

I should have mentioned that the label may, at some point, contain more than one line of text. That's why the numberOfLines is set to 0.

EDIT 3: If anybody encounters this problem -- it seems that there is a lot of difference in how underline is drawn on iOS 9 vs 10 as well as UILabel vs UITextView. I've ended up having to draw the underline myself by subclassing NSLayoutManager.


回答1:


Yes, there is such problem as you have described. It shows up when you use multiline UILabel, so not only setting numberOfLines to 0, but type more than 1 line in it.

Example

let selectedStringAttributes: [String: Any]
    = [NSFontAttributeName: UIFont.boldSystemFont(ofSize: 28),
       NSForegroundColorAttributeName: UIColor.green,
       NSUnderlineStyleAttributeName: NSUnderlineStyle.styleSingle.rawValue,
       NSUnderlineColorAttributeName: UIColor.green]

let label = UILabel(frame: CGRect(x: 100, y: 100, width: 500, height: 100))
label.numberOfLines = 0

label.attributedText = NSAttributedString(string: "String to test underline", attributes: selectedStringAttributes)

And everything will look pretty good.

But if you want to use such text:

label.attributedText = NSAttributedString(string: "String to\ntest underline", attributes: selectedStringAttributes)

or label's width is too short, than:

Not so good

So the reason for such behaviour is of course bug in NSAttributedString. As it mentioned in radar there is a workaround

You should add this attribute to your NSAttributedString

NSBaselineOffsetAttributeName: 0

And magic will happen.




回答2:


Instead of using NSAttributedString you can draw border below the label with x space using this.

let space:CGFloat = 10

let border = CALayer()
border.backgroundColor = UIColor.red.cgColor
border.frame = CGRect(x: 0, y: (label?.frame.size.height)! + space, width: (label?.frame.size.width)!, height: 1)
label?.layer.addSublayer(border)



回答3:


On my machine, showing your attributed string in a black-backgrounded UILabel, it makes a quite nice-looking display:

The red thick underline is nicely separated from the text, and is interrupted to allow the descender of the "y" to pass through it.

NOTE You cannot combine the font of the UILabel (set in Interface Builder) with its attributedText. You must set the entire label's text formatting in the attributedText. So, my code looks like this:

    let attributes : [String:Any] = [NSForegroundColorAttributeName: UIColor.white,
                      NSUnderlineStyleAttributeName: NSUnderlineStyle.styleThick.rawValue,
                      NSUnderlineColorAttributeName: UIColor.red,
                      NSFontAttributeName: UIFont.boldSystemFont(ofSize: 32)]
    let attributedString = NSAttributedString(string: "Story", attributes: attributes)
    lab.backgroundColor = .black
    lab.attributedText = attributedString

(You will notice that I removed your stipulation of the paragraph line spacing; there is only one line, so this stipulation adds nothing. However, I get the same result even if I restore it.)




回答4:


So this is my solution to this issue. I think it is "cleaner" and easier. Post me if you dont understand :)

class BottomLineTextField: UITextField {

    var bottomBorder = UIView()

    override func awakeFromNib() {
        super.awakeFromNib()
        setBottomBorder()
    }

    func setBottomBorder() {            
        self.translatesAutoresizingMaskIntoConstraints = false

        bottomBorder = UIView.init(frame: CGRect(x: 0, y: 0, width: 0, height: 0))
        hasError = false
        bottomBorder.translatesAutoresizingMaskIntoConstraints = false

        addSubview(bottomBorder)

        bottomBorder.bottomAnchor.constraint(equalTo: bottomAnchor).isActive = true
        bottomBorder.leftAnchor.constraint(equalTo: leftAnchor).isActive = true
        bottomBorder.rightAnchor.constraint(equalTo: rightAnchor).isActive = true
        bottomBorder.heightAnchor.constraint(equalToConstant: 1).isActive = true // Set underline height
    }
}


来源:https://stackoverflow.com/questions/43785665/underline-covers-text-in-nsattributedstring

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!