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!
Related
Hi guys I have small problem, I'm using func:
static func convertFromHTMLString(_ input: String?) -> NSAttributedString? {
guard let input = input else { return nil }
guard let data = input.data(using: String.Encoding.unicode, allowLossyConversion: true) else { return nil }
return try? NSAttributedString(data: data, options: [NSAttributedString.DocumentReadingOptionKey.documentType : NSAttributedString.DocumentType.html], documentAttributes: nil)
}
to read my Strings from Localizable.strings with attributes like this:
But when I run my app it looks that:
This change my Label color to black and font size to something like 10-12 ;/
My Label should have white color and font size 17, anyone know how to fix it?
Thanks ! :)
#Edit1
The solution must look like this
This is how it looks on Android.
func convertFromHTMLString(_ input: String?) -> NSAttributedString? {
guard let input = input else { return nil }
guard let data = input.data(using: String.Encoding.unicode, allowLossyConversion: true) else { return nil }
if let string = try? NSAttributedString(data: data, options: [NSAttributedString.DocumentReadingOptionKey.documentType : NSAttributedString.DocumentType.html], documentAttributes: nil).string
{
//Set color and font
let myAttribute = [ NSAttributedString.Key.foregroundColor: UIColor.white , NSAttributedString.Key.font: UIFont(name: "Chalkduster", size: 17.0)! ]
let myAttrString = NSAttributedString(string: string, attributes: myAttribute)
return myAttrString
}
return nil
}
In order to convert html to string, I use 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 ?? ""
}
}
But text what i get in API i must convert with NSAttributedString.DocumentType.html and sometime with NSAttributedString.DocumentType.plain
How can i combine these two parameters?
What those extensions do is (1) to create a Data object out of an HTML string, (2) to convert the Data object into an NSAtrributedString object. In other words, it goes like the following.
import UIKit
class ViewController: UIViewController {
// MARK: - Variables
// MARK: - IBOutlet
#IBOutlet weak var label: UILabel!
// MARK: - IBAction
override func viewDidLoad() {
super.viewDidLoad()
let htmlStr = makeHTMLString()
let data = Data(htmlStr.utf8)
if let attributedString = try?NSAttributedString(data: data, options: [.documentType: NSAttributedString.DocumentType.html], documentAttributes: nil) {
//print(attributedString.string)
label.attributedText = attributedString
}
}
func makeHTMLString() -> String {
return "<html>\n<head></head>\n<body>\n<h1>Hello, world!</h1>\n</body>\n</html>"
}
}
In the end, you don't need those extensions.
Imagine I have this json:
I could convert Json to string and show it by below code:
extension String {
var htmlToAttributedString: NSAttributedString? {
guard let data = data(using: .utf8) else { return NSAttributedString() }
do {
return try NSAttributedString(data: data, options: [.documentType: NSAttributedString.DocumentType.html, .characterEncoding:String.Encoding.utf8.rawValue], documentAttributes: nil)
} catch {
return NSAttributedString()
}
}
var htmlToString: String {
return htmlToAttributedString?.string ?? ""
}
}
but I can’t display the image in json. How can I do that?
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 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
}