I have searched a lot but can only find HTML to plain text, not the other way around, I have email implementation in my app, thus need to send the content of email as HTML to the backend.
Edit 1: I have rich text that includes bold, italic, ordered/unordered list, underlined words.
If you are looking to convert NSAttributedString to String, here is the extension method you are looking for. Simply call yourAttributtedString.htmlString() and print it out.
extension NSAttributedString {
func htmlString() -> String? {
let documentAttributes = [NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType]
do {
let htmlData = try self.data(from: NSMakeRange(0, self.length), documentAttributes:documentAttributes)
if let htmlString = String(data:htmlData, encoding:String.Encoding.utf8) {
return htmlString
}
}
catch {}
return nil
}
}
According to this post:
private func getHtmlLabel(text: String) -> UILabel {
let label = UILabel()
label.numberOfLines = 0
label.lineBreakMode = .byWordWrapping
label.attributedString = stringFromHtml(string: text)
return label
}
private func stringFromHtml(string: String) -> NSAttributedString? {
do {
let data = string.data(using: String.Encoding.utf8, allowLossyConversion: true)
if let d = data {
let str = try NSAttributedString(data: d,
options: [NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType],
documentAttributes: nil)
return str
}
} catch { }
return nil
}
Related
Here is my code which is used to convert HTML string to attributed string.
extension UILabel {
func setHTMLFromString(text: String) {
let modifiedFont = NSString(format:"<span style=\"font-family: \(self.font!.fontName); font-size: \(self.font!.pointSize)\">%#</span>" as NSString, text)
let attrStr = try! NSAttributedString(
data: modifiedFont.data(using: String.Encoding.unicode.rawValue, allowLossyConversion: true)!,
options: [NSAttributedString.DocumentReadingOptionKey.documentType:NSAttributedString.DocumentType.html, NSAttributedString.DocumentReadingOptionKey.characterEncoding: String.Encoding.utf8.rawValue],
documentAttributes: nil)
self.attributedText = attrStr
}
}
What I want to achieve is to translate the text with attributes applied to it. Below is the code for translation that I'm using to translate the simple string.
extension UIViewController {
func translate(text:String, to:TranslateLanguage, compltion: #escaping ((Bool,String?)->()) ) {
let options = TranslatorOptions(sourceLanguage: .en, targetLanguage: to)
let translator = NaturalLanguage.naturalLanguage().translator(options: options)
perform(#selector(showHudAfterTime), with: self, afterDelay: 1)
translator.downloadModelIfNeeded(with: .init(allowsCellularAccess: true, allowsBackgroundDownloading: false)) { (error) in
NSObject.cancelPreviousPerformRequests(withTarget: self)
GlobalAPI.hideLoadingHUD()
if error == nil {
translator.translate(text) { (translation, error) in
if error == nil {
compltion(true,translation)
} else {
compltion(false,text)
}
}
} else {
compltion(false,text)
}
}
}
#objc func showHudAfterTime() {
GlobalAPI.showLoadingHud()
}
}
Let me know if need any more description.
Any help would be appreciated!
I have a string that contains HTML code. What is the best way to display that (it contains images), also I want to make links in that tappable (open in Safari)
I have tried String extension that gives me NSAttributedString from HTML, but the image is only partially shown and links are not tappable.
let text = htmlString.attributedString(withRegularFont: UIFont.systemFont(ofSize: 14), andBoldFont: UIFont.systemFont(ofSize: 16))
extension String {
func attributedString(withRegularFont regularFont: UIFont, andBoldFont boldFont: UIFont, textColor: UIColor = UIColor.gray) -> NSMutableAttributedString {
var attributedString = NSMutableAttributedString()
guard let data = self.data(using: .utf8) else { return NSMutableAttributedString() }
do {
attributedString = try NSMutableAttributedString(data: data,
options: [.documentType: NSAttributedString.DocumentType.html,
.characterEncoding:String.Encoding.utf8.rawValue],
documentAttributes: nil)
let range = NSRange(location: 0, length: attributedString.length)
attributedString.enumerateAttribute(NSAttributedString.Key.font, in: range, options: .longestEffectiveRangeNotRequired) { value, range, _ in
let currentFont: UIFont = value as! UIFont
var replacementFont: UIFont? = nil
if currentFont.fontName.contains("bold") || currentFont.fontName.contains("Semibold") {
replacementFont = boldFont
} else {
replacementFont = regularFont
}
let replacementAttribute = [NSAttributedString.Key.font:replacementFont!, NSAttributedString.Key.foregroundColor: textColor]
attributedString.addAttributes(replacementAttribute, range: range)
} catch let e {
print(e.localizedDescription)
}
return attributedString
}
}
It shows me the HTML inside the UILabel but I am not able to tap on links and images are cropped respective to device width.
I think that the best option is to save this html string as a file and then load this file using web view.
check this question
In my app I want to fetch text in HTML format from the server and convert it into string to display using UILabel in another view. To convert the HTML to string I am using this extension:
extension Data{
var html2AttributedString: NSAttributedString?{
do{
return try NSAttributedString(data: self, options: [.documentType: NSAttributedString.DocumentType.html, .characterEncoding: String.Encoding.utf8.rawValue], documentAttributes: nil)
}catch{
print("error", error)
return nil
}
}
var html2String: String {
return html2AttributedString?.string ?? ""
}
}
extension String{
var html2AttributedString: NSAttributedString? {
return Data(utf8).html2AttributedString
}
var html2String: String{
return html2AttributedString?.string ?? ""
}
}
The string is called from an array like so:
text.detailText = textArray[0].html2String
However when the data is displayed onscreen the string just displays as plain text without the HTML tags. What do I need to modify in the extension to display the text properly with the tags in affect?
EDIT: the text label in text.detailText refers to another class.
In context it looks like this:
The text variable in context refers to another class. In context it looks like this:
if let otherClass = segue.destination as? otherClass {
otherClass.detailText = textArray[0].html2String
}
The other class looks like this:
class otherClass: UIViewController {
var data: Data?
#IBOutlet weak var otherDetail: UILabel!
var detailText: String = ""
override func viewDidLoad() {
super.viewDidLoad()
otherDetail?.text = detailText
}
You can see this simple example, it works. I just set label attributedText field
let htmlString = """
<p><b>This text is bold</b></p>
<p><i>This text is italic</i></p>
<p>This is<sub> subscript</sub> and <sup>superscript</sup></p>
"""
let attributedString = htmlString.data(using: .utf8).flatMap { data -> NSAttributedString? in
return try? NSAttributedString(
data: data,
options: [
.documentType: NSAttributedString.DocumentType.html,
.characterEncoding: String.Encoding.utf8.rawValue
],
documentAttributes: nil)
}
guard let attrString = attributedString else { return }
yourLabel.numberOfLines = 0
yourLabel.attributedText = attrString
Hope, this code will help you
In order to render the html tags, you should use attributed strings:
//detailText should be of type NSAttributedString
detailedText : NSAttributedString!
//replace html2String with html2AttributedString
if let otherClass = segue.destination as? otherClass {
otherClass.detailText = textArray[0].html2AttributedString
}
//and in the otherClass replace .text with .
var data: Data?
#IBOutlet weak var otherDetail: UILabel!
var detailText: NSAttributedString!
override func viewDidLoad() {
super.viewDidLoad()
otherDetail?.attributedText = detailText
}
I created a UILabel and synced its font size with a seekbar and loaded my html formatted text onto the UILabel. Unfortunately, the format gets removed if I change the font size of my UILabel using seekbar.
I used this approach, from garie, that was answered from another thread
private func getHtmlLabel(text: String) -> UILabel {
let label = UILabel()
label.numberOfLines = 0
label.lineBreakMode = .byWordWrapping
label.attributedString = stringFromHtml(string: text)
return label
}
private func stringFromHtml(string: String) -> NSAttributedString? {
do {
let data = string.data(using: String.Encoding.utf8, allowLossyConversion: true)
if let d = data {
let str = try NSAttributedString(data: d,
options: [NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType],
documentAttributes: nil)
return str
}
} catch {
}
return nil
}
Link: Swift: Display HTML data in a label or textView
Is there any approach I could use to retain the my html formatted text?
EDIT #1:
This is how I resize my UILabel.
#IBOutlet weak var textLabel: UILabel!
#IBAction func resizeText(_ sender: UISlider) {
textLabel.font = UIFont.systemFont(ofSize: CGFloat(sender.value) * 20.0)
}
The HTML data I'm passing onto my UILabel:
<html><body><b>hello world</b></body></html>
This is the formatted HTML data on UILabel:
After resizing the UILabel, it loses its format:
EDIT #2:
Tried Milan's answer but encountered an error. Unresolved identifier in NSAttributedStringKey
Here's my code:
import UIKit
class GalleryViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
textLabel.attributedText = stringFromHtml()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
#IBOutlet weak var textLabel: UILabel!
#IBAction func resizeText(_ sender: UISlider) {
if let attributedText = textLabel.attributedText {
let newAttributedText = NSMutableAttributedString(attributedString: attributedText)
newAttributedText.setFontSize(newSize: CGFloat(sender.value) * 20.0)
textLabel.attributedText = newAttributedText
}
}
private func stringFromHtml() -> NSAttributedString? {
do {
let string = "<html><body><b>hello world</b></body></html>"
let data = string.data(using: String.Encoding.utf8, allowLossyConversion: true)
if let d = data {
let str = try NSAttributedString(data: d,
options: [NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType],
documentAttributes: nil)
return str
}
} catch {
}
return nil
}
}
extension NSMutableAttributedString {
func setFontSize(newSize: CGFloat) {
beginEditing()
self.enumerateAttribute(NSAttributedStringKey.font, in: NSRange(location: 0, length: self.length)) { (value, range, stop) in
if let f = value as? UIFont {
let newFont = f.withSize(newSize)
removeAttribute(NSAttributedStringKey.font, range: range)
addAttribute(NSAttributedStringKey.font, value: newFont, range: range)
}
}
endEditing()
}
}
Setting the font directly messes up your attributed text. You will have to set font size on the attributedText:
#IBAction func resizeText(_ sender: UISlider) {
if let attributedText = textLabel.attributedText {
let newAttributedText = NSMutableAttributedString(attributedString: attributedText)
newAttributedText.setFontSize(newSize: CGFloat(sender.value) * 20.0)
textLabel.attributedText = newAttributedText
}
}
For this to work you will need following extension on NSMutableAttributedString:
extension NSMutableAttributedString {
func setFontSize(newSize: CGFloat) {
beginEditing()
self.enumerateAttribute(NSAttributedStringKey.font, in: NSRange(location: 0, length: self.length)) { (value, range, stop) in
if let f = value as? UIFont {
let newFont = f.withSize(newSize)
removeAttribute(NSAttributedStringKey.font, range: range)
addAttribute(NSAttributedStringKey.font, value: newFont, range: range)
}
}
endEditing()
}
}
Try using UserDefaults to save the the NSAttributedString returning from second function:
1- Hold the attributed text in a variable
let attributedText = stringFromHtml(string: String)
2- Save it in UserDefaults
UserDefaults.standard.set(attributedText, forKey: "attributedText")
And for retrieving it you may use this format to safely unwrap the value:
if let text = UserDefaults.standard.object(forKey: "attributedText") as? NSAttributedString {
label.attributedString = text
}
I want to display text in Italic ,bold which is received from server .
< p > < b > < i > hello < /i > < /b > < i >world< /i >< /p > so,
responseObj!["text"] = "<p><b><i>hello</i></b><i>world</></p>"
if let postText:String = responseObj!["text"] as? String{
let str = try NSAttributedString(data: postText.data(using: String.Encoding.unicode, allowLossyConversion: true)!, options: [ NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType], documentAttributes: nil)
self.textView.attributedText = str
}
when i am adding like this means my text displays normal without applying bold & italic . I want text to be displayed in bold ,italic .
EDIT: Updated Swift 4
Create an extension for String:
extension String {
func htmlAttributedString(fontSize: CGFloat = 17.0) -> NSAttributedString? {
let fontName = UIFont.systemFont(ofSize: fontSize).fontName
let string = self.appending(String(format: "<style>body{font-family: '%#'; font-size:%fpx;}</style>", fontName, fontSize))
guard let data = string.data(using: String.Encoding.utf16, allowLossyConversion: false) else { return nil }
guard let html = try? NSMutableAttributedString (
data: data,
options: [NSAttributedString.DocumentReadingOptionKey.documentType: NSAttributedString.DocumentType.html],
documentAttributes: nil) else { return nil }
return html
}
}
Invoke it anywhere in your project:
text.htmlAttributedString() // will set fontSize with 17.0 which is the default value
text.htmlAttributedString(fontSize: 14.0) // pass your required fontSize
Note, that let string = self.appending(String(format: "<style>body{font-family: '%#'; font-size:%fpx;}</style>", fontName, fontSize)) is used to keep the string font as same as the font used in default iOS platform.
To set the string on UITextView use:
textView.attributedText = textToBeConverted.htmlAttributedString() ?? ""
RESULT:
Assign Attributed text to UITextView from below function,
//HTML to Attributed text
func stringFromHtml(string: String) -> NSAttributedString? {
do {
let data = string.data(using: String.Encoding.utf8, allowLossyConversion: true)
if let d = data {
let str = try NSAttributedString(data: d,
options: [NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType],
documentAttributes: nil)
return str
}
} catch {
}
return nil
}
//This will give you attributed text which you have to assign to your UITextView. and whatever string having html tag that you have to pass inside this function.
//Below code will conver attributed text to HTML Text
//Attributed to HTML text
let attrStr = self.txtView.attributedText
let documentAttributes = [NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType]
do {
let htmlData = try attrStr?.data(from: NSMakeRange(0, (attrStr?.length)!), documentAttributes:documentAttributes)
if let htmlString = String(data:htmlData!, encoding:String.Encoding.utf8) {
print(htmlString)
}
}
catch {
print("error creating HTML from Attributed String")
}