My image
I am getting data from Html to the text.
Now please tell me how to avoid the space between two paragraphs ?
func processGetDescriptionResponse(json: JSON) {
let status = json.dictionaryObject!["status"] as? Bool
if status == true {
let data = json.dictionaryValue["data"]!
let values = data.arrayValue
dataSourceDescription.removeAll()
for i in 0 ..< values.count {
let description = Description.initWithJSON(values[i])
dataSourceDescription.append(description)
// DetailDescription.text = dataSourceDescription[i].content
if dataSourceDescription[i].file_url == ""
{
DetailImage.image = UIImage(named: "logo_two_fifty")
}
else
{
let imageURL = NSURL(string: baseURLString + dataSourceDescription[i].file_url!)
DetailImage.kf_setImageWithURL(imageURL!, placeholderImage: nil, optionsInfo: [.Transition(ImageTransition.Fade(50))]) { (image, error, cacheType, imageURL) in
}
}
DetailDescription.attributedText = convertText(dataSourceDescription[i].content!)
print(DetailDescription.text)
}
} else {
}
}
If you receive html content, you can display it in UITextView using NSAttributedString:
let htmlString = "<html><body><p>Para 1</p><p>Para 2</p></body></html>"
let attributedString = try!
NSAttributedString(data: htmlString.dataUsingEncoding(NSUnicodeStringEncoding, allowLossyConversion: false)!,
options: [NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType],
documentAttributes: nil)
yourTextView.attributedText = attributedString
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
}
I want to display a string(which is actually a small HTML code, with hyperlink) on UILabel. E.g. The string which I have to display is: "Click here to know more". So is there a way to display it on UILabel, and on clicking the hyperlink(Click here) it opens up the desired web page?
Here's what I did:
#IBOutlet weak var testLabel: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
let htmlData = NSString(string: "Click here to know more").data(using: String.Encoding.unicode.rawValue)
let attributedString = try? NSAttributedString(data: htmlData!, options: [.documentType: NSAttributedString.DocumentType.html], documentAttributes: nil)
testLabel.attributedText = attributedString
}
The label displayed the string just like I wanted, but on clicking the hyperlink, it didn't do what what desired, i.e. open a web page.
Try to use UITextView instead of UILabel
#IBOutlet weak var testTextView: UITextView!
override func viewDidLoad() {
super.viewDidLoad()
testTextView.isEditable = false
testTextView.dataDetectorTypes = .link
testTextView.isScrollEnabled = false
let htmlData = NSString(string: "Click here to know more").data(using: String.Encoding.unicode.rawValue)
let attributedString = try? NSAttributedString(data: htmlData!, options: [.documentType: NSAttributedString.DocumentType.html], documentAttributes: nil)
testTextView.attributedText = attributedString
}
#IBOutlet weak var testLabel: UILabel!
let message = "Please <a href='https://www.google.com'>click here</a> to search"
#override func viewDidLoad() {
super.viewDidLoad()
formatLabel(with: message.htmlToString)
}
func formatLabel(with message: String) {
let formattedText = String.format(strings: ["click here"],
boldFont: UIFont.init(name: "Roboto-Bold", size: 16.0)!,
boldColor: UIColor.blue,
inString: message,
font: UIFont.init(name: "Roboto-Regular", size: 16.0)!,
color: UIColor(red: 33/255, green: 136/255, blue: 189/255, alpha: 1.0))
testLabel.attributedText = formattedText
testLabel.numberOfLines = 0
let tap = UITapGestureRecognizer(target: self, action: #selector(handleTermTapped))
testLabel.addGestureRecognizer(tap)
testLabel.isUserInteractionEnabled = true
testLabel.textAlignment = .center
}
#objc func handleTermTapped(gesture: UITapGestureRecognizer) {
let clickString = (testLabel.text ?? "") as NSString
let clickRange = clickString.range(of: "click here")
let tapLocation = gesture.location(in: testLabel)
let index = testLabel.indexOfAttributedTextCharacterAtPoint(point: tapLocation)
if checkRange(clickRange, contain: index) == true {
guard let url = URL(string: "https://www.google.com") else { return }
UIApplication.shared.open(url, options: [:], completionHandler: nil)
return
}
}
Helper function and extensions:
func checkRange(_ range: NSRange, contain index: Int) -> Bool {
return index > range.location && index < range.location + range.length
}
extension String {
static func format(strings: [String],
boldFont: UIFont = UIFont.init(name: "Roboto-Bold", size: 16.0)!,
boldColor: UIColor = UIColor.blue,
inString string: String,
font: UIFont = UIFont.init(name: "Roboto-Regular", size: 16.0)!,
color: UIColor = UIColor(red: 33/255, green: 136/255, blue: 189/255, alpha: 1.0)) -> NSAttributedString {
let attributedString =
NSMutableAttributedString(string: string,
attributes: [
NSAttributedString.Key.font: font,
NSAttributedString.Key.foregroundColor: color])
let boldFontAttribute = [NSAttributedString.Key.font: boldFont, NSAttributedString.Key.foregroundColor: boldColor]
for bold in strings {
attributedString.addAttributes(boldFontAttribute, range: (string as NSString).range(of: bold))
}
return attributedString
}
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 ?? ""
}
}
extension UILabel {
func indexOfAttributedTextCharacterAtPoint(point: CGPoint) -> Int {
let textStorage = NSTextStorage(attributedString: self.attributedText!)
let layoutManager = NSLayoutManager()
textStorage.addLayoutManager(layoutManager)
let textContainer = NSTextContainer(size: self.frame.size)
textContainer.lineFragmentPadding = 0
textContainer.maximumNumberOfLines = self.numberOfLines
textContainer.lineBreakMode = self.lineBreakMode
layoutManager.addTextContainer(textContainer)
let index = layoutManager.characterIndex(for: point, in: textContainer, fractionOfDistanceBetweenInsertionPoints: nil)
return index
}
}
Here is simple demo of how to do what you need with UILabel
import UIKit
class ViewController : UIViewController {
override func loadView() {
let view = UIView()
view.backgroundColor = .white
let label = UILabel()
label.frame = CGRect(x: 150, y: 200, width: 200, height: 20)
label.attributedText = NSAttributedString(string: "Tap Me", attributes: [.link : URL(string: "http://www.google.com")!])
label.isUserInteractionEnabled = true
label.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(handleLink(_:))))
view.addSubview(label)
self.view = view
}
#IBAction func handleLink(_ sender: UIGestureRecognizer) {
guard sender.state == .ended else { return }
guard let label = sender.view as? UILabel else { return }
guard let link = label.attributedText?.attribute(.link, at: 0, effectiveRange: nil) as? URL else { return }
UIApplication.shared.open(link, options: [:], completionHandler: nil)
}
}
I have used this code to formatting HTML content on UILabel
var htmlToAttributedString: NSAttributedString? {
do {
guard let data = data(using: String.Encoding.utf8) else {
return nil
}
return try NSAttributedString(data: data, options: [.documentType: NSAttributedString.DocumentType.html, .characterEncoding: String.Encoding.utf8.rawValue], documentAttributes: nil)
} catch {
print("error: ", error)
return nil
}
}
My HTML Content Like:
("<p>My Name is <b>Ayush</b> <I>Bansal</I></p>")
When I used above code for formatting then I get output like (My Name is Ayush Bansal).
But I want my output will be like this (My Name is Ayush Bansal)
you can use this extension
extension String {
func convertToAttributed(_ defaultFont: UIFont, textColor: UIColor ) -> NSAttributedString? {
guard let data = "".replacingOccurrences(of: "\n", with: "<br>").data(using: .utf8, allowLossyConversion: false) else { return nil }
guard let attributedString = try? NSMutableAttributedString(data: data,
options: [NSAttributedString.DocumentReadingOptionKey.documentType: NSAttributedString.DocumentType.html],
documentAttributes: nil)
else { return nil }
attributedString.enumerateAttribute(NSAttributedString.Key.font,
in: NSRange(location: 0, length: attributedString.length),
options: NSAttributedString.EnumerationOptions(rawValue: 0))
{ (value, range, _) -> Void in
if let oldFont = value as? UIFont {
var newFont = defaultFont
let isBold = oldFont.fontName.lowercased().contains("bold")
let isItalic = oldFont.fontName.lowercased().contains("italic")
if isBold && isItalic {
newFont = UIFont.bolditalicFont(ofSize: 14)
} else if isBold {
newFont = UIFont.boldFont(ofSize: 14)
} else if isItalic {
newFont = UIFont.italicFont(ofSize: 14)
}
attributedString.removeAttribute(NSAttributedString.Key.font, range: range)
attributedString.addAttribute(NSAttributedString.Key.font, value: newFont, range: range)
attributedString.addAttribute(NSAttributedString.Key.foregroundColor, value: textColor, range: range)
}
}
}
}
usage:
yourLabel.attributedText = string.convertToAttributed(font, textColor: textcolor)
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")
}
I'm using this way and it works fine, but has a slowness fallback because of the usage of NSHTMLTextDocumentType as i did my research
do {
let attributedOptions:[String: Any] = [
NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType,
NSCharacterEncodingDocumentAttribute: String.Encoding.utf8.rawValue]
let date = html.data(using: String.Encoding.utf8, allowLossyConversion: true)!
return try NSAttributedString(data: data, options: attributedOptions , documentAttributes: nil)
} catch let error as NSError {
print("htmo2String \(error)")
}
any ideas how to do it faster or another efficient way to do it!
Maybe you can execute the parse code on a queue...
func parse(_ html: String, completionHandler: #escaping (_ attributedText: NSAttributedString?) -> (Void)) -> Void
{
let htmlData = text.data(using: String.Encoding.utf8, allowLossyConversion: false)
let options: [String: AnyObject] = [
NSDocumentTypeDocumentAttribute : NSHTMLTextDocumentType as AnyObject
]
completionHandler(try? NSAttributedString(data: htmlData!, options: options, documentAttributes: nil))
}
And now call the function and wait from response...
let queue: DispatchQueue = DispatchQueue(label: "com.yourcompany.Process./html_converter")
queue.async
{
parse("<p>¡Hola mundo</p>", completionHandler: { (attributtedString: NSAttributedString?) -> (Void) in
if let attributtedString = attributtedString
{
DispatchQueue.main.async
{
print("str:: \(attributtedString)")
}
}
})
}
Did you try o use a UIWebView to present HTML content ?
You can display HTML from a string or from a URL, as you prefer.
Here is an example to display HTML from a string :
string sHTMLContent = "<html><head><body><p>Hello World</p></body></head></html>";
m_WebView.LoadHtmlString(sHTMLContent , null);
Then you can set the size of your Webview to be equal to your textview with constraints. The webview will be scrollable automatically if needed.
Final string extension to show html string efficiently with #Adolfo async idea
with the ability to change font and color ^_^
extension String {
func html2StringAsync(_ fontSize: CGFloat? = nil, color: UIColor? = nil, completionBlock:#escaping (NSAttributedString) ->()) {
let fontSize = fontSize ?? 10
let fontColor = color ?? UIColor.black
let font = "Avenir !important"
let html = "<div style=\"font-family:\(font); font-size:\(fontSize)pt; color:\(fontColor.hexString);\">" + self + "</div>"
if let data = html.data(using: String.Encoding.utf8, allowLossyConversion: true){
DispatchQueue.main.async {
do {
let attributedOptions:[String: Any] = [NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType,
NSCharacterEncodingDocumentAttribute: String.Encoding.utf8.rawValue]
let attrStr = try NSAttributedString(data: data, options: attributedOptions , documentAttributes: nil)
completionBlock(attrStr)
} catch let error as NSError {
print("htmo2String \(error)")
}
}
}else{
completionBlock(NSAttributedString(string: self))
}
}
}