2

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

remy boys
  • 2,928
  • 5
  • 36
  • 65

1 Answers1

7

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 = words.map({
        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.sizeToFit()
    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 = attribWords.map { 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
    }

    view.addSubview(label)
    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()
attribWords.forEach{
    attribString.appendAttributedString(NSAttributedString(string: "  "))
    attribString.appendAttributedString($0)
}
textView.attributedText = attribString
beyowulf
  • 15,101
  • 2
  • 34
  • 40
  • @beyouWulf thanks man its working pretty fine , am wondering can we calculate the height of all Labels (combined) ? any idea how can we ? – remy boys Jun 12 '16 at 06:19
  • 1
    I updated my answer. It's easies to just get it after you finish laying out the labels. You could combine the `for` loop snippet and the `if let` snippet into one function like `layoutLabelsAndResizeView` or something like that. – beyowulf Jun 12 '16 at 14:20