developercool7 developercool7 - 2 months ago 8
Swift Question

How to add a text to every line on a UITextView

I am having a hard time solving this. My goal is to add a specific text to every line of the textview. So far my app has been working well, but when I click to add the text it keeps adding to the first line of the text view only, I wanna be able to make it add to every line of the textview. So far I have this:

@IBAction func alertView(sender: AnyObject) {
textToCopy.selectedRange = NSMakeRange(0,0)
textToCopy.text = "test\(textToCopy.text)"


Any help would be appreciated, thanks!

Answer

This problem has a bit of complexity to it. So we should break it down into more specific parts.

  1. Write a function to calculate the height of a textView containing a string with a certain font and a certain width.

  2. Break the string of the textView into an array of words separated by spaces, assuming the line breaks by word and not character.

  3. Rebuild a string by incrementally adding each word back on to find where the height changes are using our function from part 1.

Part 1: Calculating height of text based off fixed width

func textHeight(text:String, attrib:[String: AnyObject], width:CGFloat) -> CGFloat{
    let formattedString = NSMutableAttributedString(string: text)
    formattedString.setAttributes(attrib, range: NSMakeRange(0, count(text)))
    return textViewHeightFromAttributedString(formattedString, width)
}

func textViewHeightFromAttributedString(text:NSAttributedString, width:CGFloat) -> CGFloat{
    //we could be more efficient by only creating this tempView once.
    let tempView = UITextView()
    tempView.attributedText = text;
    let size = tempView.sizeThatFits(CGSizeMake(width, 10000))
    return size.height
}

Part 2: Break down text into word array, and note font as attribute array and the width of the UITextView.

let textContent = "I can only imagine what long string would go here. I can only imagine what long string would go here. I can only imagine what long string would go here"

let parts = textContent.componentsSeparatedByString(" ");
var attrs = [NSFontAttributeName : UIFont.systemFontOfSize(19.0)]
let textViewWidth:CGFloat =  100;

Part 3: Append each word back together one at a time to figure out where the new line occurs so we can append the line prefix.

let linePrefix = "ALERT:"
var adjusted   = linePrefix
var lastHeight = textHeight(adjusted, attrs, textViewWidth)

for part in parts{

    let spacePart = " " + part
    let newHeight = textHeight(adjusted + spacePart, attrs, textViewWidth)

    if newHeight > lastHeight{
        adjusted += "\n" + linePrefix + spacePart;
        lastHeight = newHeight
    }else{
        adjusted += spacePart;
    }
}

Now put adjusted back into your textView!

One optimization you could also make here is to reuse the tempView in the first method instead of recreating it each time, but I'll leave that change up to you.. as it really depends on how efficient you actually need to be.