下划线覆盖 NSAttributedString 中的文本

Posted

技术标签:

【中文标题】下划线覆盖 NSAttributedString 中的文本【英文标题】:Underline covers text in NSAttributedString 【发布时间】:2017-05-04 14:27:35 【问题描述】:

我正在尝试创建一个属性字符串,但下划线覆盖了我的文本,而不是出现在它后面:

有没有办法解决这个问题?我正在使用以下代码:

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)

谢谢!

编辑:

提供更多上下文:

我在 .xib 文件中的 UILabel 上显示属性字符串:

view.textLabel.attributedText = attributedString

标签具有以下字体: 系统粗体 32.0

我在 iPhone 6 - ios 10.3 模拟器上运行代码。

编辑 2:

我应该提到标签在某些时候可能包含多于一行的文本。这就是 numberOfLines 设置为 0 的原因。

编辑 3: 如果有人遇到这个问题 - 在 iOS 9 和 10 以及 UILabel 和 UITextView 上绘制下划线的方式似乎存在很大差异。我最终不得不通过继承 NSLayoutManager 自己绘制下划线。

【问题讨论】:

无法重现问题。在我的机器上,下划线很好地与文本分开,并且不与“y”的下降线相交。 i.stack.imgur.com/uXs4R.png 请显示更多您的代码,以使其可重现。你如何显示这个属性字符串?你用的是什么字体?以此类推。 这里也一样,我也无法在我的机器上复制您的问题。它与文本很好地分开。 @Grzegorz Aperliński (另外我可能会提到您的代码没有在我的机器上编译。有必要将attributes明确声明为[String:Any]类型。) 在主条目中添加了更多详细信息。 查看我修改后的答案。您不能在 Interface Builder 中设置 font,但在 attributedText 中设置其他所有内容;您必须在您的attributedString 中包含字体规范in。正如我修改后的答案所示,当你这样做时,一切都很好。 【参考方案1】:

是的,存在您所描述的问题。它在你使用多行UILabel 时出现,因此不仅将numberOfLines 设置为0,而且在其中输入多于1 行。

示例

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)

一切都会看起来不错。

但如果你想使用这样的文字:

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

或者标签的宽度太短,比:

Not so good

所以出现这种行为的原因当然是bug in NSAttributedString。正如它在雷达中提到的,有一个解决方法

您应该将此属性添加到您的NSAttributedString

NSBaselineOffsetAttributeName: 0

魔法就会发生。

【讨论】:

谢谢!我实际上已经使用 NSLayoutManager 的子类实现了自定义绘图。希望这个问题能在未来得到解决。【参考方案2】:

除了使用 NSAttributedString 之外,您还可以使用它在标签下方用 x 空间绘制边框。

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】:

在我的机器上,以黑色背景的 UILabel 显示您的属性字符串,它的显示效果非常漂亮:

红色粗下划线很好地与文本分开,并被打断以允许“y”的下行穿过它。

注意 您不能将 UILabel(在 Interface Builder 中设置)的 font 与其 attributedText 结合使用。您必须在attributedText 中设置整个 标签的文本格式。所以,我的代码如下所示:

    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

(你会注意到我删除了你对段落行距的规定;只有一行,所以这个规定没有增加任何内容。但是,即使我恢复它,我也会得到相同的结果。)

【讨论】:

谢谢!实际上,我注意到代码中设置的字体粗细和 IB 之间几乎没有区别,至少在渲染方面。我终于找到了问题的根源(并编辑了原始条目)——如果您将行数设置为 0,就会出现问题。对不起,我应该提到我正在更改它,但认为它不相关...【参考方案4】:

所以这是我对这个问题的解决方案。 我认为它“更清洁”和更容易。 如果你不明白,请给我留言:)

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
    

【讨论】:

这个方案只要只有一行文字就可以了。 嗨@GrzegorzAperliński,你说得对。我这样做只是为了一行

以上是关于下划线覆盖 NSAttributedString 中的文本的主要内容,如果未能解决你的问题,请参考以下文章

UIButton 上的 iOS NSAttributedString

如何快速下划线 UILabel?

UILabel:自定义下划线颜色?

用另一个 NSAttributedString 替换 NSAttributedString 的子字符串

ios: NSAttributedString 分配错误

使用 NSAttributedString 设置字体