Search code examples
swift3nsattributedstringnsrange

Swift 3: How to apply attributes to parts of string


So the method I used in Swift 2 no longer works because of changes in Swift 3, regarding String indices and ranges. Previously I had

func configureLabel(defaultColor: UIColor, highlightColor: UIColor, boldKeyText: Bool) {
    if let index = self.text?.characters.indexOf(Character("|")) {
        self.text = self.text!.stringByReplacingOccurrencesOfString("|", withString: "")
        let labelLength:Int = Int(String(index))! // Now returns nil

        var keyAttr: [String:AnyObject] = [NSForegroundColorAttributeName: highlightColor]
        var valAttr: [String:AnyObject] = [NSForegroundColorAttributeName: defaultColor]
        if boldKeyText {
            keyAttr[NSFontAttributeName] = UIFont.systemFontOfSize(self.font.pointSize)
            valAttr[NSFontAttributeName] = UIFont.systemFontOfSize(self.font.pointSize, weight: UIFontWeightHeavy)
        }

        let attributeString = NSMutableAttributedString(string: self.text!)
        attributeString.addAttributes(keyAttr, range: NSRange(location: 0, length: (self.text?.characters.count)!))
        attributeString.addAttributes(valAttr, range: NSRange(location: 0, length: labelLength))

        self.attributedText = attributeString

    }
}

Basically I would be able to take a string like "First Name:| Gary Oak" and have all the parts before and after the | character be different colors, or make part of it bold, but the line I commented above no longer returns a value, which breaks everything else afterwards. Any ideas on how to do this?


Solution

  • In Swift 3 you can use something like this:

    func configureLabel(defaultColor: UIColor, highlightColor: UIColor, boldKeyText: Bool) {      
    
        if let index = self.text?.characters.index(of: Character("|")) {
            self.text = self.text!.replacingOccurrences(of: "|", with: "")
            let position = text.distance(from: text.startIndex, to: index)
    
            let labelLength:Int = Int(String(describing: position))!
    
            var keyAttr: [String:AnyObject] = [NSForegroundColorAttributeName: defaultColor]
            var valAttr: [String:AnyObject] = [NSForegroundColorAttributeName: highlightColor]
            if boldKeyText {
                keyAttr[NSFontAttributeName] = UIFont.systemFont(ofSize: self.font.pointSize)
                valAttr[NSFontAttributeName] = UIFont.systemFont(ofSize: self.font.pointSize, weight: UIFontWeightHeavy)
            }
    
            let attributeString = NSMutableAttributedString(string: self.text!)
            attributeString.addAttributes(keyAttr, range: NSRange(location: 0, length: (self.text?.characters.count)!))
            attributeString.addAttributes(valAttr, range: NSRange(location: 0, length: labelLength))
    
            self.attributedText = attributeString
    
        }
    
    }
    

    the main idea that using let position = text.distance(from: text.startIndex, to: index) you got not the integer representation of string position but the string Index value. Using text.distance(from: text.startIndex, to: index) you can find int position for string Index