remy boys remy boys -5 years ago 361
iOS Question

convert a String to NSAttributedString in a specific manner

so i have a String which looks like this :

Swift , VisualBasic , Ruby

i wanna convert this string to something like this :
enter image description here

basically i wanna create a background behind a single word , yeah i can use the NSTokenField libraries for getting this behaviour but my text is not manually entered by user its pre structured (from an array) and i dont want the whole behaviour of NSTokeField i just want the appearance like this and selection (by selection i mean to clear a word at one single tap on backspace , the whole word not a letter )

well i know how to change the colour of a text something like this

func getColoredText(text: String) -> NSMutableAttributedString {
let string:NSMutableAttributedString = NSMutableAttributedString(string: text)
let words:[String] = text.componentsSeparatedByString(" ")
var w = ""

for word in words {
if (word.hasPrefix("{|") && word.hasSuffix("|}")) {
let range:NSRange = (string.string as NSString).rangeOfString(word)
string.addAttribute(NSForegroundColorAttributeName, value: UIColor.redColor(), range: range)
w = word.stringByReplacingOccurrencesOfString("{|", withString: "")
w = w.stringByReplacingOccurrencesOfString("|}", withString: "")
string.replaceCharactersInRange(range, withString: w)
return string

but i dont know how to achieve what i want if somebody can provide me some guidance then it'll be so helpful for me

P.s if my question is not clear enough then please let me know i'll add some more details

Answer Source

It's going to be much easier to just use several UILabels if you want to get rounded corners.

If that's acceptable you can first generate an array of attributed strings like:

func getAttributedStrings(text: String) -> [NSAttributedString]
    let words:[String] = text.componentsSeparatedByString(" , ")

    let attributes = [NSForegroundColorAttributeName: UIColor.whiteColor(), NSBackgroundColorAttributeName: UIColor.blueColor()]

    let attribWords ={
        return NSAttributedString(string: " \($0) ", attributes: attributes)
    return attribWords

For each attributed string we need to create UILabel. To do so we can create a function that passes in an NSAttributedString and returns a UILabel:

func createLabel(string:NSAttributedString) ->UILabel
    let label = UILabel()
    label.backgroundColor = UIColor.blueColor()
    label.attributedText = string
    label.layer.masksToBounds = true
    label.layer.cornerRadius = label.frame.height * 0.5
    return label

Now we'll convert our input string into labels by saying:

let attribWords = getAttributedStrings("Java , Swift , JavaScript , Objective-C , Ruby , Pearl , Lisp , Haskell , C++ , C")
let labels = { string in
        return createLabel(string)

Now we just need to display them in a view:

let buffer:CGFloat = 3.0
var xOffset:CGFloat = buffer
var yOffset:CGFloat = buffer

let view = UIView(frame: CGRect(x: 0.0, y: 0.0, width: 320.0, height: 400.0))
view.backgroundColor = UIColor.lightGrayColor()

for label in labels
    label.frame.origin.x = xOffset
    label.frame.origin.y = yOffset

    if label.frame.maxX > view.frame.maxX
        xOffset = buffer
        yOffset += label.frame.height + buffer

        label.frame.origin.x = xOffset
        label.frame.origin.y = yOffset

    xOffset += label.frame.width + buffer

We can also at this point resize our view to the height of the labels by saying:

if let labelHeight = labels.last?.frame.height
    view.frame.height = yOffset + labelHeight + buffer

Throwing this code in a swift playground results in: enter image description here

If you can't use labels, if you want an editable UITextView for example, I would give up on rounded corners and just say something like:

let attribWords = getAttributedStrings("Java , Swift , JavaScript , Objective-C , Ruby , Pearl , Lisp , Haskell , C++ , C")
let attribString = NSMutableAttributedString()
    attribString.appendAttributedString(NSAttributedString(string: "  "))
textView.attributedText = attribString
Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download