Change color of NSAttributedString and open its link in safari - swift

From server I get a string with html tag, it's like that:
"It's a test - Apple""
I use this function to convert it to NSAttributedString.
func convertHtmlTagsToString(text: String) {
let attributedString = Data(text.utf8)
if let attributedString = try? NSAttributedString(data: attributedString, options: [.documentType: NSAttributedString.DocumentType.html], documentAttributes: nil) {
label.attributedText = attributedString
}
}
My first problem is I can't change the color of the label text, it's black, and my second problem is, how I can make the url part clickable that I can open safari with that link.
Thank you so much.

Related

Data to attributedString with font attributes Swift

I have an RTF file with which I was able to get contents as Data (i want it to be in Data to use it elsewhere in code). Howeever, I would like to add styling to the attributedString like font before assigning to label. Im struck on how to apply these attributes in below code. Please advice how i can achieve same. Here's my code
let rtfData = getRTFData()
guard let data = rtfData else {
return
}
if let attributedString = try? NSAttributedString(data: data, options: [.documentType: NSAttributedString.DocumentType.rtf], documentAttributes: nil) {
myLabel.attributedText = attributedString
}
Here i wanted to add attributes to attributedString like
let boldAttributes: [NSAttributedString.Key: Any] = [.font: UIFont.boldSystemFont(ofSize: 14)] and apply these attributes to attributedText
If you want to append font attribute to existing attributes this one should work:
if let attributedString = try? NSMutableAttributedString(data: data, options: [.documentType: NSAttributedString.DocumentType.rtf], documentAttributes: nil) {
var attrs = attributedString.attributes(at: 0, effectiveRange: nil)
attrs[NSAttributedString.Key.font] = UIFont.boldSystemFont(ofSize: 14)
attributedString.setAttributes(attrs, range: NSRange(location: 0, length: attributedString.length))
myLabel.attributedText = attributedString
}

How to transfer HTML text into an attributed string without losing line breaks in Swift 3 [duplicate]

This question already has answers here:
HTML Format in UITextView
(8 answers)
Closed 5 years ago.
Please do not mark as duplicate. None of the existing questions solves not losing line breaks.
Given String: "Regular text becomes <b>bold with </b>\n\n<b><i>An italic</i></b>\n\n<b>Linebreak</b>"
I have two options:
let attrStr = try! NSAttributedString(
data: story.body.data(using: String.Encoding.unicode, allowLossyConversion: true)!,
options: [ NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType,
NSFontAttributeName: Handler.shared.setFont(FontNames.sourceSerifProRegular, 25.0)],
documentAttributes: nil)
This option loses the font, size and the line breaks.
The following extension from this answer, keeps UILabel's font, but it loses the line breaks as well.
extension UILabel {
func _slpGetSize() -> CGSize? {
return (text as NSString?)?.size(attributes: [NSFontAttributeName: font])
}
func setHTMLFromString(htmlText: String) {
let modifiedFont = NSString(format:"<span style=\"font-family: \(self.font!.fontName); font-size: \(self.font!.pointSize)\">%#</span>" as NSString, htmlText) as String
let attrStr = try! NSAttributedString(
data: modifiedFont.data(using: .unicode, allowLossyConversion: true)!,
options: [NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType, NSCharacterEncodingDocumentAttribute: String.Encoding.utf8.rawValue],
documentAttributes: nil)
self.attributedText = attrStr
}
}
label.setHTMLFromString(htmlText: story.body)
What am I missing? What do I need to do to keep the line breaks?
Help is very appreciated.
Try set numberOfLines property in the UILabel.
For that, you can count the number of break lines and set into numberOfLines.
extension UILabel {
func _slpGetSize() -> CGSize? {
return (text as NSString?)?.size(attributes: [NSFontAttributeName: font])
}
func setHTMLFromString(htmlText: String) {
let modifiedFont = NSString(format:"<span style=\"font-family: \(self.font!.fontName); font-size: \(self.font!.pointSize)\">%#</span>" as NSString, htmlText) as String
let attrStr = try! NSAttributedString(
data: modifiedFont.data(using: .unicode, allowLossyConversion: true)!,
options: [NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType, NSCharacterEncodingDocumentAttribute: String.Encoding.utf8.rawValue],
documentAttributes: nil)
self.attributedText = attrStr
self.numberOfLines = htmlText.components(separatedBy: "\n").count
}
}
I hope this example help you.

How do I create a NSAttributedString from HTML in Swift 3? [duplicate]

i'm quite new to iOS Development and right now working on an app which receive some kind of JSON Data. But some Backend Experts thought, that it would be better for the User if they just copy the Information straight out of Word and paste it into the information System. So I'm sitting here, trying to make a clickable Link in a UITableView.
I parse the data from Web and get a String with this format:
Für mehr Informationen klicken sie here.
I tried already a UILabel, but after some research I use now the often suggested UITextView. In the Attributed Inspector, i set it as an Attributed Text and enabled the Link Detection. Now the text is shown red and is clickable.
The Problem now for me is, that the HTML Tags and the correct (German) Character Set is still missing and i got no idea, how to display it in the right way.
The shown string is parsed in this way:
func showHTMLString(unformattedString: String) -> NSAttributedString{
var attrStr = NSAttributedString(
data: tmpString.dataUsingEncoding(NSUnicodeStringEncoding, allowLossyConversion: true)!,
options: [ NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType],
documentAttributes: nil,
error: nil)
return attrStr!
}
If i fill the Textview with attrStr?.string the Format is shown in the correct way but the link is gone as well.
Any suggestions how to format the shown string in the right way?
Thanks in advance
AR4G4
The problem there is that you have to change the Character Encoding options from NSUnicodeStringEncoding to NSUTF8StringEncoding to load your of your html the proper way. I think you should create a string extension read-only computed property to convert your html code to attributed string:
Xcode 8.3.1 • Swift 3.1
extension Data {
var attributedString: NSAttributedString? {
do {
return try NSAttributedString(data: self, options:[NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType, NSCharacterEncodingDocumentAttribute: String.Encoding.utf8.rawValue], documentAttributes: nil)
} catch {
print(error)
}
return nil
}
}
extension String {
var data: Data {
return Data(utf8)
}
}
let htmlStringCode = "Für mehr Informationen klicken sie here"
htmlStringCode.data.attributedString?.string ?? "" // "Für mehr Informationen klicken sie here"
in your case
yourTextView.attributedText = htmlStringCode.data.attributedString
Check the attributes of your UITextView in IB. In order for the links to work, you must have Selectable checked.
I would recommend displaying HTML in a UIWebView. It is more robust than using a UITextView. See Display html text in uitextview for more information.
I used code for Swift 4:
var descriptionStr : String = String() //Dynamic text
let regex = try! NSRegularExpression(pattern: "<.*?>", options: [.caseInsensitive])
let range = NSRange(location: 0, length: descriptionStr.count)
let htmlLessString: String = regex.stringByReplacingMatches(in: descriptionStr, options: NSRegularExpression.MatchingOptions(), range:range, withTemplate: "")
textViewRef.text = htmlLessString
Having created your attributed string, you would then set the attributedText property of the UITextView to be the NSAttributedString itself, not the string property of that attributed string.
Your versions is pretty close to begin with. As Leonardo Savio Dabus stated you should probably try NSUTF*StringEncoding. The following produces your expected output for me. As he said, you might want to add it to an extension of string, if you are doing this a lot.
let theString = "Für mehr Informationen klicken sie here."
let theAttributedString = NSAttributedString(data: str.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: true)!,
options: [NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType], documentAttributes: nil, error: nil)
theTextView.attributedText = atString
Another way I used to do this :
var someHtmlString = "Für mehr Informationen klicken sie here."
let regex = try! NSRegularExpression(pattern: "<.*?>", options: [.CaseInsensitive])
let range = NSRange(location: 0, length: someHtmlString.characters.count)
let htmlLessString: String = regex.stringByReplacingMatchesInString(someHtmlString, options: NSMatchingOptions(), range:range, withTemplate: "")
End result -> htmlLessString is
"Für mehr Informationen klicken sie here."
I had an app that had a UITextView where I wanted to be able to paste html formatted text from the browser and then save it as a string(containing html formatting) to the database, and then another time retrieve it from the database and show it with the same format as it was first copied from the website.
I managed this by making these two extensions:
extension String
{
func getAttributedStringFromHTMLString() -> NSAttributedString
{
do {
let attributedString = try NSAttributedString(data: self.dataUsingEncoding(NSUnicodeStringEncoding, allowLossyConversion: true)!, options: [NSDocumentTypeDocumentAttribute : NSHTMLTextDocumentType], documentAttributes: nil)
return attributedString
} catch {
print(error)
return NSAttributedString()
}
}
}
extension NSAttributedString
{
func getHTMLString() -> String
{
var htmlText = "";
let documentAttributes = [NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType]
do {
let htmlData = try self.dataFromRange(NSMakeRange(0, self.length), documentAttributes:documentAttributes)
if let htmlString = String(data:htmlData, encoding:NSUTF8StringEncoding) {
htmlText = htmlString
}
return htmlText
}
catch {
print("error creating HTML from Attributed String")
return ""
}
}
}

Text in between <b></b> programmatic bold string in between and nilling<b></b> UILabel swift

I have core data objects that contain strings that have as markers to make that part of code bold. Is there anyway way of checking for these things in swift making the in between text bold and making the code invisible to the user? I am still new to coding and new to swift language. How would you go about doing this? This is for iOS.
var str = "<b>Hello, playground</b>"
do{
let atrString = try NSAttributedString(data:str.dataUsingEncoding(NSUTF8StringEncoding)!, options: [NSDocumentTypeDocumentAttribute:NSHTMLTextDocumentType], documentAttributes: nil)
}catch{
print("Could not convert!")
}
You will first need to convert the text to NSData using dataUsingEncoding() than try to make a NSAttributedString with an HTML Text document type
Swift 5 version of milo526 answer.
do{
let atrString = try NSAttributedString(data: str.data(using: .utf8) ?? .init(), options: [.documentType: NSAttributedString.DocumentType.html], documentAttributes: nil)
}catch{
print("Could not convert!")
}

HTML inside of textView

I want to paste HTML text(with p, br, bgcolor etc.) inside of textView. I did try the next:
var bodyText = NSAttributedString(data: body.dataUsingEncoding(NSUnicodeStringEncoding, allowLossyConversion: true)!, options: [NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType], documentAttributes: nil, error: nil)
postBody.text = bodyText
postBody -> textView. But it prints the next error:
Cannot assign a value of type 'NSAttributedString?' to a value of type 'String!'
How can I correctly print it inside of textView?
Instead of text, use attributedText.
postBody.attributedText = bodyText
Or, if you just want the text without the attributes, use NSAttributedString's string property.
postBody.text = bodyText?.string