问题:NSAttributedString需要一个NSRange,而我正在使用一个使用范围的Swift字符串

let text = "Long paragraph saying something goes here!"
let textRange = text.startIndex..<text.endIndex
let attributedString = NSMutableAttributedString(string: text)

text.enumerateSubstringsInRange(textRange, options: NSStringEnumerationOptions.ByWords, { (substring, substringRange, enclosingRange, stop) -> () in

    if (substring == "saying") {
        attributedString.addAttribute(NSForegroundColorAttributeName, value: NSColor.redColor(), range: substringRange)
    }
})

产生以下错误:

错误:'Range'不能转换为'NSRange' attributedString。addAttribute(NSForegroundColorAttributeName,值:NSColor.redColor(),范围:substringRange)


当前回答

可能的解决方案

Swift提供了distance()来测量开始和结束之间的距离,可以用来创建一个NSRange:

let text = "Long paragraph saying something goes here!"
let textRange = text.startIndex..<text.endIndex
let attributedString = NSMutableAttributedString(string: text)

text.enumerateSubstringsInRange(textRange, options: NSStringEnumerationOptions.ByWords, { (substring, substringRange, enclosingRange, stop) -> () in
    let start = distance(text.startIndex, substringRange.startIndex)
    let length = distance(substringRange.startIndex, substringRange.endIndex)
    let range = NSMakeRange(start, length)

//    println("word: \(substring) - \(d1) to \(d2)")

        if (substring == "saying") {
            attributedString.addAttribute(NSForegroundColorAttributeName, value: NSColor.redColor(), range: range)
        }
})

其他回答

斯威夫特4

我认为有两种方法。

1. NSRange(范围,在:)

2. NSRange(location:, length:)

示例代码:

let attributedString = NSMutableAttributedString(string: "Sample Text 12345", attributes: [.font : UIFont.systemFont(ofSize: 15.0)])

// NSRange(range, in: )
if let range = attributedString.string.range(of: "Sample")  {
    attributedString.addAttribute(.foregroundColor, value: UIColor.orange, range: NSRange(range, in: attributedString.string))
}

// NSRange(location: , length: )
if let range = attributedString.string.range(of: "12345") {
    attributedString.addAttribute(.foregroundColor, value: UIColor.green, range: NSRange(location: range.lowerBound.encodedOffset, length: range.upperBound.encodedOffset - range.lowerBound.encodedOffset))
}

屏幕截图:

对我来说,这非常有效:

let font = UIFont.systemFont(ofSize: 12, weight: .medium)
let text = "text"
let attString = NSMutableAttributedString(string: "exemple text :)")

attString.addAttributes([.font: font], range:(attString.string as NSString).range(of: text))

label.attributedText = attString
func formatAttributedStringWithHighlights(text: String, highlightedSubString: String?, formattingAttributes: [String: AnyObject]) -> NSAttributedString {
    let mutableString = NSMutableAttributedString(string: text)

    let text = text as NSString         // convert to NSString be we need NSRange
    if let highlightedSubString = highlightedSubString {
        let highlightedSubStringRange = text.rangeOfString(highlightedSubString) // find first occurence
        if highlightedSubStringRange.length > 0 {       // check for not found
            mutableString.setAttributes(formattingAttributes, range: highlightedSubStringRange)
        }
    }

    return mutableString
}

我的解决方案是一个字符串扩展,首先获得快速范围,然后获得从字符串的开始到子字符串的开始和结束的距离。

然后使用这些值计算子字符串的开始和长度。然后我们可以将这些值应用到NSMakeRange构造函数。

这个解决方案适用于由多个单词组成的子字符串,这里使用enumerateSubstrings的许多解决方案让我失望。

extension String {

    func NSRange(of substring: String) -> NSRange? {
        // Get the swift range 
        guard let range = range(of: substring) else { return nil }

        // Get the distance to the start of the substring
        let start = distance(from: startIndex, to: range.lowerBound) as Int
        //Get the distance to the end of the substring
        let end = distance(from: startIndex, to: range.upperBound) as Int

        //length = endOfSubstring - startOfSubstring
        //start = startOfSubstring
        return NSMakeRange(start, end - start)
    }

}

Swift 3扩展变体,保留现有属性。

extension UILabel {
  func setLineHeight(lineHeight: CGFloat) {
    guard self.text != nil && self.attributedText != nil else { return }
    var attributedString = NSMutableAttributedString()

    if let attributedText = self.attributedText {
      attributedString = NSMutableAttributedString(attributedString: attributedText)
    } else if let text = self.text {
      attributedString = NSMutableAttributedString(string: text)
    }

    let style = NSMutableParagraphStyle()
    style.lineSpacing = lineHeight
    style.alignment = self.textAlignment
    let str = NSString(string: attributedString.string)

    attributedString.addAttribute(NSParagraphStyleAttributeName,
                                  value: style,
                                  range: str.range(of: str as String))
    self.attributedText = attributedString
  }
}