I am reading strings out of a Localizable.strings which contains something like that which is basically what you have in an strings.xml of an Android app
"testShort" = "A <b>short</b>\ntest with another<b>bold text</b>";
The bold and and line feed are the only two formatting attributes I have in my texts. I am trying to develop a method like this for days now without success:
func ConvertText(inputText: String) -> NSAttributedString {
// here comes the conversion to a representation with Helvetica 14pt and Helvetica-Bold 14pt including line feeds.
}
My final goal is to display the text in an UITextView's attributedText.
Being kinda new to Swift and iOS without knowing Objective-C I found its very difficult to do String manipulations as they are quite different and complex and all examples are in Objective-C. What makes it even harder is that most API methods are not available or different in Swift than in Objective-C...
Here is what I tried so far for the method body with the help of a lot of other posts here:
var test = inputText.dataUsingEncoding(NSUnicodeStringEncoding, allowLossyConversion: true)!
attrStr = NSAttributedString(
data: test,
options: [NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType],
documentAttributes: nil,
error: nil)!
return attrStr
The main issues here are that \n
isn't converted and the font is very small and different.
Next I tried to manually bold a part of a text. It seem to work like that:
var newText = NSMutableAttributedString(string: inputText)
newText.addAttribute(NSFontAttributeName, value: UIFont(name: "Helvetica-Bold", size: 14.0)!, range: NSRange(location:2,length:4))
Now I tried to search for the attributes in the text, deleting them and use the addAttribute kinda like that
// Start of bold text
var range = newText.rangeOfString("<b>")!
// End of bold text
var range2 = newText.rangeOfString("</b>")!
// replacing attributes
newText = newText.stringByReplacingCharactersInRange(range, withString: "")
newText = newText.stringByReplacingCharactersInRange(range2, withString: "")
// creating a range for bold => error "'String.Index' is not convertible to 'int'"
// how to do such a thing
var boldRange = NSMakeRange(range.startIndex, range2.endIndex -3)
// setting bold
newText.addAttribute(NSFontAttributeName, value: UIFont(name: "Helvetica-Bold", size: 14.0)!, range: boldRange)
This whole range thing is my main issue at the moment as its quite different to a simple position in the string.
This issue is a great example for the lack of (or well hidden) documentation:
The addAttribute
wants an NSRange, the rangeOfString
seems to deliver a generic Range according to an error message I get - but there is no info about it.
The Search Documentation button in Xcode on rangeOfString()
leads to NSString.
Searching in there for rangeOfString()
says it returns NSRange
. Clicking on that leads to the info of a type alias for _NSRange
which in turn has two NSUInteger properties named location
and length
. Where is the startIndex and endIndex property I see in XCode? Very confusing...
Would be great if you can give me some snippets or hints where I'm wrong here or even the method body as I'm still hoping its not too difficult if you know iOS and Swift well. I'm aiming for iOS 7.1 support but if its way easier with iOS 8 only its fine as well.
Regarding your first method with
NSAttributedString
:\n
character in HTML is just ordinary white space. To get a line break you would have to replace it by<br />
first.<span>
, see Parsing HTML into NSAttributedText - how to set font?.This gives (now updated for Swift 2):
Regarding your second method:
There are two different
rangeOfString()
methods, one for (Swift)String
and one for (Foundation)NSString
. TheString
method returns aRange<String.Index>
and theNSString
method returns anNSRange
.Converting between these two is possible but complicated. The reason is that in a
String
each "extended grapheme cluster" counts as one character, whereas inNSString
each UTF-16 unit is counted. An extended grapheme cluster can be one or more UTF-16 unit ("" is two UTF-16 units, "" is four).The
addAttribute()
method accepts only anNSRange
. The easiest method to solve this problem is to convert the Swift string toNSString
and work withNSRange
only. Then your method could look like this: