First wanna say thank you before if this can be solved..so i have textview that get the data with html tag..so i use attributedText and function to render html..it worked..but i need to change the font family..right now by default it "times new roman" i want to change to "Helvetica" any clue? i use the extension for this :
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)
}}
then i use it with :
cell.txtview.attributedText = contentText.data.attributedString
it worked but the font default become "times new roman" i need to change it..any idea? i am very appreciate it before..thank you!
enter image description here
I also already try this...see image below
enter image description here
Your attributed string must be like below :
using this link
let data = "vini".data(using: .utf8)
let attributedString = data!.attributedString
let newAttributedString = NSMutableAttributedString(attributedString: (attributedString)!)
newAttributedString.enumerateAttribute(NSFontAttributeName, in: NSMakeRange(0, (newAttributedString.length)), options: []) { value, range, stop in
guard let currentFont = value as? UIFont else {
return
}
let fontDescriptor = currentFont.fontDescriptor.addingAttributes([UIFontDescriptorFamilyAttribute: "Helvetica"])
if let newFontDescriptor = fontDescriptor.matchingFontDescriptors(withMandatoryKeys: [UIFontDescriptorFamilyAttribute]).first {
let newFont = UIFont(descriptor: newFontDescriptor, size: currentFont.pointSize)
newAttributedString.addAttributes([NSFontAttributeName: newFont], range: range)
}
}
print(newAttributedString)
Related
I am getting HTML formatted string from API response, so I need to set it to a label while maintaining Custom Font(as of my App) and also applying a style(bold, regular, etc.) to the label.
I have used an extension that enables to convert the HTML string to regular string with newlines etc. but, I was able to set font here, but only one font and it shows in regular font only, so the whole label is in one font, what I want is to set bold font to the bold HTML part and regular to regular HTML part/tag.
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
}
}
//set converted html to string here
let whyAttendAttributedText: NSMutableAttributedString = NSMutableAttributedString(attributedString: attendData.whyAttendData?.desc?.htmlToAttributedString ?? NSAttributedString())
//set font here
whyAttendAttributedText.addAttributes([NSMutableAttributedString.Key.font: CommonSettings.shared.getFont(type: .regular, size: descriptionLabel.font.pointSize), NSMutableAttributedString.Key.foregroundColor: UIColor.white], range: NSMakeRange(0, whyAttendAttributedText.length))
I want to set bold and regular to the text, but as I have set only one font I was unable to get the result, is there any way to set the bold and regular font as in HTML string?
This should help :
extension String {
func attributedString(withRegularFont regularFont: UIFont, andBoldFont boldFont: UIFont) -> 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("Bold") {
replacementFont = boldFont
} else {
replacementFont = regularFont
}
let replacementAttribute = [NSAttributedString.Key.font:replacementFont!]
attributedString.addAttributes(replacementAttribute, range: range)
}
} catch let e {
print(e.localizedDescription)
}
return attributedString
}
}
Let's assume your string after parsing HTML string is: "This is your HTML string"
To create an attributed string,
let attrStr = NSMutableAttributedString(string: "This is your HTML string")
Adding UIFont attribute with value as System-Regular,
attrStr.addAttribute(.font, value: UIFont.systemFont(ofSize: 14.0, weight: .regular), range: NSRange(location: 0, length: attrStr.length))
Whenever adding an attribute to the attributed string, we need to provide the range of string in which we want to reflect the attribute.
Since we need the whole string to have Regular font, so the range is calculated as the whole string length.
Now, adding UIFont attribute with value as System-Bold to a part of the string, let's say we make HTML as bold,
attrStr.addAttribute(.font, value: UIFont.systemFont(ofSize: 14.0, weight: .bold), range: (attrStr.string as NSString).range(of: "HTML"))
We've calculated the range of HTML word within the whole string.
Similarly, you can add any of the attributes to the string giving the relevant range values.
Output: This is yourHTMLstring
Edit-1:
To calculate the range of <b> to </b> you need to calculate it manually.
Example:
let str = "This <b>is your HTML</b> string"
let range1 = (str as NSString).range(of: "<b>")
let range2 = (str as NSString).range(of: "</b>")
let requiredRange = NSRange(location: range1.location, length: range2.location + range2.length - range1.location)
The above example will work for single instance of <b>/</b> in the string.
Edit-2:
When string includes multiple instances of <b>/</b>:
let htmlStr = "This is an <b>HTML</b> parsed <b>string</b>"
let arr = htmlStr.components(separatedBy: "</b>")
let attrStr = NSMutableAttributedString()
for str in arr {
if !str.isEmpty {
let range1 = (str as NSString).range(of: "<b>")
let requiredRange = NSRange(location: range1.location, length: str.count - range1.location)
let formattedStr = NSMutableAttributedString(string: str)
formattedStr.addAttribute(.font, value: UIFont.systemFont(ofSize: 14.0, weight: .bold), range: requiredRange)
attrStr.append(formattedStr)
attrStr.append(NSAttributedString.init(string: "</b>", attributes: [.font : UIFont.systemFont(ofSize: 14.0, weight: .bold)]))
}
}
self.label.attributedText = attrStr
Output: This is an<b>HTML</b>parsed<b>string</b>
Applying Bold and other different styles to the text can be done using below method.
extension String {
func attributedString(with style: [NSAttributedString.Key: Any]? = nil,
and highlightedText: String,
with highlightedTextStyle: [NSAttributedString.Key: Any]? = nil) -> NSAttributedString {
let formattedString = NSMutableAttributedString(string: self, attributes: style)
let highlightedTextRange: NSRange = (self as NSString).range(of: highlightedText as String)
formattedString.setAttributes(highlightedTextStyle, range: highlightedTextRange)
return formattedString
}
}
Input: "This is a test message"
Expectd Output: "This is a test message"
This can be achieved as follows.
let sampleInput = "This is a test message"
let boldtext = "test"
let output = sampleInput.attributedString(with: [.font: UIFont.systemFont(ofSize: 12.0, weight: .regular)],
and: boldtext, with: UIFont.systemFont(ofSize: 12.0, weight: .bold))
Different styles can be applied using different attribute keys. Hope this helps.
I am using UITextView to show following text:
txtTest.userInteractionEnabled = true;
txtTest.selectable = true
txtTest.dataDetectorTypes = .Link;
txtTest.text = "<p>لتيتنظربهاإلىالأمورتؤثربنجاحكفيالعملفعلًاأتعرفالقولالمأثورالقديملاتنظرللنصفالفارغمنالكأسوالطريقةالتيتنظربهاإلىالأمورتؤثربنجاحكفيالعملفعلًا</p>رابط خارجي external link"
UITextView link is not tappable on text رابط خارجي external link. Tappable area goes somewhere else in the UITextView. I just figured out it by tapping random locations on UITextView
Don't know is it the bug of UITextView or something is missing from my side. If anyone experienced the same issue and found any solution?
You will have to make your UIViewController confirm to UITextViewDelegate protocol and implement textView(_:shouldInteractWith:in:interaction:). your standard UITextView setup should look something like this, don't forget the delegate and dataDetectorTypes.
txtTest.delegate = self
txtTest.isUserInteractionEnabled = true // default: true
txtTest.isEditable = false // default: true
txtTest.isSelectable = true // default: true
txtTest.dataDetectorTypes = [.link]
UITextViewDelegate method shouldInteractWithURL:
func textView(_ textView: UITextView, shouldInteractWith URL: URL, in characterRange: NSRange, interaction: UITextItemInteraction) -> Bool {
print("Link Selected!")
return true
}
and instead of using anchor tag use attributedText to detect link in your selected text in swift way.
let targetLink = "https://google.com"
let yourAttributes = [NSForegroundColorAttributeName: UIColor.black, NSFontAttributeName: UIFont.systemFont(ofSize: 15)]
let yourOtherAttributes = [NSForegroundColorAttributeName: UIColor.red, NSFontAttributeName: UIFont.systemFont(ofSize: 25)]
let partOne = NSMutableAttributedString(string: "لتيتنظربهاإلىالأمورتؤثربنجاحكفيالعملفعلًاأتعرفالقولالمأثورالقديملاتنظرللنصفالفارغمنالكأسوالطريقةالتيتنظربهاإلىالأمورتؤثربنجاحكفيالعملفعلً ", attributes: yourAttributes)
let partTwo = NSMutableAttributedString(string: " رابط خارجي external link", attributes: yourOtherAttributes)
let text = " رابط خارجي external link"
let str = NSString(string: text)
let theRange = str.range(of: text)
partTwo.addAttribute(NSLinkAttributeName, value: targetLink, range: theRange)
let combination = NSMutableAttributedString()
combination.append(partOne)
combination.append(partTwo)
txtTest.attributedText = combination
if you want to use HTML then you still have to convert it to NSAttributedString. This function will convert all the HTML tags into NSAttributedString.
extension String{
func convertHtml() -> NSAttributedString{
guard let data = data(using: .utf8) else { return NSAttributedString() }
do{
return try NSAttributedString(data: data, options: [NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType, NSCharacterEncodingDocumentAttribute: String.Encoding.utf8.rawValue], documentAttributes: nil)
}catch{
return NSAttributedString()
}
}
}
then you can use it like so.
let stringValue = "<p>لتيتنظربهاإلىالأمورتؤثربنجاحكفيالعملفعلًاأتعرفالقولالمأثورالقديملاتنظرللنصفالفارغمنالكأسوالطريقةالتيتنظربهاإلىالأمورتؤثربنجاحكفيالعملفعلًا</p>رابط خارجي external link"
txtTest.attributedText = stringValue.convertHtml()
I looked around SO and couldn't find this exact problem, despite there being a few questions with similar titles.
All I want to do is have some matching text on UILabel be drawn in BOLD. I'm using it when I'm searching for objects, it should 'bolden' the search term. To this aim, I wrote the following code:
extension String {
func boldenOccurrences(of searchTerm: String?, baseFont: UIFont, textColor: UIColor) -> NSAttributedString {
let defaultAttributes: [String : Any] = [NSForegroundColorAttributeName : textColor,
NSFontAttributeName: baseFont]
let result = NSMutableAttributedString(string: self, attributes: defaultAttributes)
guard let searchTerm = searchTerm else {
return result
}
guard searchTerm.characters.count > 0 else {
return result
}
// Ranges. Crash course:
//let testString = "Holy Smokes!"
//let range = testString.startIndex ..< testString.endIndex
//let substring = testString.substring(with: range) // is the same as testString
var searchRange = self.startIndex ..< self.endIndex //whole string
var foundRange: Range<String.Index>!
let boldFont = UIFont(descriptor: baseFont.fontDescriptor.withSymbolicTraits(.traitBold)!, size: baseFont.pointSize)
repeat {
foundRange = self.range(of: searchTerm, options: .caseInsensitive , range: searchRange)
if let found = foundRange {
// now we have to do some stupid stuff to make Range compatible with NSRange
let rangeStartIndex = found.lowerBound
let rangeEndIndex = found.upperBound
let start = self.distance(from: self.startIndex, to: rangeStartIndex)
let length = self.distance(from: rangeStartIndex, to: rangeEndIndex)
log.info("Bolden Text: \(searchTerm) in \(self), range: \(start), \(length)")
let nsRange = NSMakeRange(start, length)
result.setAttributes([NSForegroundColorAttributeName : textColor,
NSFontAttributeName: boldFont], range: nsRange)
searchRange = found.upperBound ..< self.endIndex
}
} while foundRange != nil
return result
}
}
Everything "looks" fine. The log statement spits out what I expect and it's all good. However, when drawn on the UILabel, sometimes an entire string is set to bold, and I don't understand how that could be happening. Nothing in the code suggests this should be happening.
I set the result of this above method in a typical UITableCell configuration method (i.e. tableView(cellForRowAt indexPath:.... ) )
cell.titleLabel.attributedText = artist.displayName.emptyIfNil.boldenOccurrences(of: source.currentSearchTerm, baseFont: cell.titleLabel.font, textColor: cell.titleLabel.textColor)
Your primary issue is the cell reuse, maybe when a cell is reused keep your font bold as font, and that is why you have this issue, you can solve this in your cell prepareForReuse() method you can add
override func prepareForReuse() {
super.prepareForReuse()
//to fix ipad Error
self.titleLabel.font = UIFont(name: "YourBaseFont", size: yourFontSize)
}
Trying to display a ASTextNode (same as UILabel from AsyncDisplayKit) to display an html text. I simply have to set the label's attributed text.
There is how i work my string :
Using this extension i transform the HTML text into a NSAttributedString :
extension String {
var html2AttributedString: NSAttributedString? {
guard let data = data(using: .utf8) else { return nil }
do {
return try NSAttributedString(data: data, options: [NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType, NSCharacterEncodingDocumentAttribute: String.Encoding.utf8.rawValue], documentAttributes: nil)
} catch let error as NSError {
print(error.localizedDescription)
return nil
}
}
var html2String: String {
return html2AttributedString?.string ?? ""
}
}
Then i set my label details :
self.displayContent = NSMutableAttributedString(attributedString: content.html2AttributedString!)
self.displayContent?.addAttribute(NSFontAttributeName, value: UIFont.fontMainFeedContentFont(), range: NSRange.init(location: 0, length: self.displayContent!.length))
So i have my label with my font and it's ok, problem is that i can't change the links colors of my label, it's a system blue that i do want.
Any idea how can i change the links' colors ?
Thanks.
I found an answer for this in Swift 4.0
termsAndPolicyTextView.linkTextAttributes = [
NSAttributedString.Key.foregroundColor: UIColor.red
]
Full code:
Note: I can't set multiple color in a single textView.
let attributedString = NSMutableAttributedString(string: termsAndPolicyText)
attributedString.addAttribute(
NSAttributedString.Key.link,
value: "https://google.co.in",
range: (termsAndPolicyText as NSString).range(of: "Terms or service")
)
attributedString.addAttribute(
NSAttributedString.Key.link,
value: "https://google.co.in", // Todo set our terms and policy link here
range: (termsAndPolicyText as NSString).range(of: "Privacy & Legal Policy")
)
attributedString.addAttributes(
[NSAttributedString.Key.foregroundColor: UIColor.NMSTextColor(with: 0.6)],
range: NSRange(location: 0, length: termsAndPolicyText.count)
)
termsAndPolicyTextView.linkTextAttributes = [
NSAttributedString.Key.foregroundColor: UIColor.termstextViewTextColor()
]
termsAndPolicyTextView.attributedText = attributedString
termsAndPolicyTextView.textAlignment = .center
Ok guys, i found an ugly way to do this.
After transforming the html text to an NSMutableAttributedString, i simply loop thought all attributes, when i see an "NSLink" attribute i simply add an attribute for the attribute's range :
self.myString!.enumerateAttributes(in: NSRange(0..<myString!.length), options: []) { (attributes, range, _) -> Void in
for (attribute, object) in attributes {
if attribute == "NSLink" {
print("Attribute = \(attribute) -- \(object)")
self.myString?.addAttribute(NSForegroundColorAttributeName, value: StyleKit.color_blue_bright, range: range)
self.myString?.addAttribute(NSUnderlineColorAttributeName, value: UIColor.clear, range: range)
}
}
}
The link color can be changed in the following way. The below example will demonstrate that:
let attributedText:NSMutableAttributedString = NSMutableAttributedString(string: "why?")
attributedText.addAttribute(NSUnderlineStyleAttributeName, value: NSUnderlineStyle.styleSingle, range: NSMakeRange(0, attributedText.length))
attributedText.addAttribute(NSUnderlineColorAttributeName, value: UIColor.black, range: NSMakeRange(0, attributedText.length))
attributedText.addAttribute(NSForegroundColorAttributeName, value: UIColor.black, range: NSMakeRange(0, attributedText.length))
Also, you have to make the following changes to the UITextView that's displaying it.
textView.linkTextAttributes = [NSForegroundColorAttributeName : UIColor.black]
If you do not want to use UITextView to do this, you can simply use TTTAttributedLabel. It has linkAttributes and activeLinkAttributes property which you can use to achieve the desired behaviour without using UITextView.
Please let me know if it works or not. Feel free to suggest edits to make this better :)
Links color is default of attributed string. Can be specified by using css.
extension String {
var html2AttributedString: NSAttributedString? {
let html = """
<style type="text/css">
a, a:link, a:visited {
color: inherit !important;
}
</style>
""" + self
guard let data = html.data(using: .utf8) else { return nil }
...
I am using this extension of String to get proper attributed text from the HTML tags in a String.
extension String {
var html2AttributedString: NSAttributedString? {
guard
let data = dataUsingEncoding(NSUTF8StringEncoding)
else { return nil }
do {
return try NSAttributedString(data: data, options: [NSDocumentTypeDocumentAttribute:NSHTMLTextDocumentType,NSCharacterEncodingDocumentAttribute:NSUTF8StringEncoding ], documentAttributes: nil)
} catch let error as NSError {
print(error.localizedDescription)
return nil
}
}
var html2String: String {
return html2AttributedString?.string ?? ""
}
}
And I am using the value in a UILabel inside a UICollectionView.
if let value = mainNote.html2AttributedString
{
cell.note.attributedText = value
}
else
{
cell.note.text = mainNote
}
This method works great. But by default it comes with the "Times New Roman" font with size of 11. So I wanted to make it little bigger. I tried using NSMutableAttributedString.
if let value = mainNote.html2AttributedString
{
let mutableString = NSMutableAttributedString(string: value.string, attributes: [NSFontAttributeName : UIFont(name: "Times New Roman", size: 20)!])
cell.note.attributedText = mutableString
}
else
{
cell.note.text = mainNote
}
Which actually did nothing.
If I increase the font size of UILabel directly then the font size gets increased but the italic attribute does not work.
cell.note.font = UIFont(name: "Times New Roman", size: 16)
Please help me out here to make the String little bigger.
Use this updated extension:
extension String {
func html2AttributedString(font: UIFont?) -> NSAttributedString? {
guard
let data = dataUsingEncoding(NSUTF8StringEncoding)
else { return nil }
do {
let string = try NSAttributedString(data: data, options: [NSDocumentTypeDocumentAttribute:NSHTMLTextDocumentType, NSCharacterEncodingDocumentAttribute: NSUTF8StringEncoding], documentAttributes: nil)
let newString = NSMutableAttributedString(attributedString: string)
string.enumerateAttributesInRange(NSRange.init(location: 0, length: string.length), options: .Reverse) { (attributes : [String : AnyObject], range:NSRange, _) -> Void in
if let font = font {
newString.removeAttribute(NSFontAttributeName, range: range)
newString.addAttribute(NSFontAttributeName, value: font, range: range)
}
}
return newString
} catch let error as NSError {
print(error.localizedDescription)
return nil
}
}
var html2String: String {
return html2AttributedString(nil)?.string ?? ""
}
}
Usage:
if let value = mainNote.html2AttributedString(UIFont(name: "Times New Roman-ItalicMT", size: 20))
{
cell.note.attributedText = value
}
else
{
cell.note.text = mainNote
}