UITextView or UILabel with html hyperlinks - ios

I need text with multiple tapeable links init.
In Android I just used simple html string for that
Example:
"Photo The owner / CC BY-SA 3.0"
And it worked only when I clicked on words corresponding links.
I spent a day and did not manage to find simple solution for ios.
I tried to use extension for UITextView :
extension UITextView {
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 paragraph = NSMutableParagraphStyle()
paragraph.alignment = .center
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
}
But links work not only when I click on the hyperlink world but also when I click on simple text between. And I did not manage to align this text in textView(center) as well.
Does anybody know correct way?

Can't find documentation at the moment, but close observation indicates:
Because tapping with a finger is not as precise as clicking with a mouse pointer, the link gets a larger "tap region" than the text itself.
With your example - "Photo The owner / CC BY-SA 3.0" - I can tap on the ow characters without triggering either link. If my tap is on The it triggers the Photo link, if my tap is on new / it triggers that link.
Edit
One option to center the text...
In your extension, change
let modifiedFont = NSString(format:"<span style=\"font-family: \(self.font!.fontName); font-size: \(self.font!.pointSize)\">%#</span>" as NSString, text)
to
let modifiedFont = NSString(format:"<p style=\"text-align:center\"><span style=\"font-family: \(self.font!.fontName); font-size: \(self.font!.pointSize)\">%#</span></p>" as NSString, text)
added the <p style=... tag.

Related

Format part of text in TextField

I have implemented a text field in my iOS App and now I want a different formation for a passage of the text.
I find in the forum the suggestion to use the following code:
var temp:String = "Hello World"
let attrsBold = [NSFontAttributeName : UIFont.boldSystemFont(ofSize: 15)]
let txTeam1 = NSMutableAttributedString(string: temp, attributes: attrsBold)
What now happened is, that the text is not formatted but is written with the following information in the text field:
HelloWorld{NSFont =” font-familiy:
\”.SFUIText-Semibold\”;font-weight: bold; font-style: normal;
font-size: 15.00pt”;}
The text is set to the text field as follows:
textBericht.text = gameResult[0].bericht
The variable gameResult is written by a function:
gameResult = game.calculateGame(basic: gameBasic)
What I doing wrong? It seems the app is not interpreting the text after "Hello World".
You must set the text with
textBericht.attributedText = temp

String with multilpe attributes in swift

I am working on an app on which i had to make the text in a UITextView bold or italic or underlined. So i came up with this solution to make the selected range from the textView bold. The same way i can make it italic and but not underlined, don't know how.
//MARK: Bold Bar Button
func boldBarButtonClicked(sender : UIBarButtonItem)
{
if let selectedTextRange = self.textView.selectedTextRange
{
let beginningOfDocument = self.textView.beginningOfDocument
let startingPoint = self.textView.offsetFromPosition(beginningOfDocument, toPosition: selectedTextRange.start)
let selectedTextLength = self.textView.offsetFromPosition(selectedTextRange.start, toPosition: selectedTextRange.end)
let dict : Dictionary<String, AnyObject> = self.textView.textStorage.attributesAtIndex(startingPoint, effectiveRange: nil)
if let currentFont = dict[NSFontAttributeName] as? UIFont
{
let fontDescriptor = currentFont.fontDescriptor()
let changedFontDescriptor = fontDescriptor.fontDescriptorWithSymbolicTraits(UIFontDescriptorSymbolicTraits.TraitBold)
let updatedFont = UIFont(descriptor: changedFontDescriptor, size: 0.0)
let updatedDict = [NSFontAttributeName : updatedFont ]
self.textView.textStorage.beginEditing()
let selectedNSRange = NSMakeRange(startingPoint, selectedTextLength)
self.textView.textStorage.setAttributes(updatedDict, range: selectedNSRange)
self.textView.textStorage.endEditing()
// Put bold tag inside letters
}
}
}
So basically when the user sees the textView i have to make the text bold. So i thought of putting the text in between bold tag just the same as html. So that i can loop through the characters and see whether there is any text which is bold or italic or underline.
Am i doing it the correct way? Finding the selected range make it bold or italic or underlined and then put the tag inside the reference string, finally passing this string to the server with tags involved, so that others can see where comes the bold or italic or underlined characters.
How this will work if the same string has multiple attributes like, if the string "alvin" has bold and italic and underline, it will be like U I B "alvin' /U /I /B (tags are same as html bold, italic, underline) correct? How can i do find these in Swift, i thought about it a lot and tired of using regular expressions and looping through the string. But could not get the proper result. Thanks in advance.

NSAttributeString battling css scripting already in a string

Okay I'm having an issue with NSAttributeString. I'm getting different html/css strings that occupy "busDescriptio" depending on what business you choose from a website database. I'm able to customize the string as I see fit as NSAttributeString but unfortunately on some cases the string already has css scripting in it which overrides my style that I insert into the string. Is it possible to override the scripting that is within my string? If so, how would I be able to do this? ***If I cant override the script can I just extract a certain tag from my string or replace it? Oh here is what my string looks like. As you see their is a style that is being poppulated within the string aka(busDescriptio). I'm not able to change that with regular scripting using NSAttributeString.
/* This is a random description my busDescriptio pulls in which changes everytime someone selects a different business*/<p><span style="color:rgb(0, 0, 0); font-family:verdana,arial,tahoma; font-size:12px">Baxter Eye Care has been serving The Woodlands with quality eye care and personal friendly service since 1981. Dr. Baxter, Dr. Daniels and Dr. Shosa are dedicated to your eye health and vision needs.</span></p>
This is the code I'm using to do this
extension String {
var html2String:String {
return NSAttributedString(data: dataUsingEncoding(NSUTF8StringEncoding)!, options: [NSDocumentTypeDocumentAttribute:NSHTMLTextDocumentType,NSCharacterEncodingDocumentAttribute:NSUTF8StringEncoding], documentAttributes: nil, error: nil)!.string
}
var html2NSAttributedString:NSAttributedString {
return NSAttributedString(data: dataUsingEncoding(NSUTF8StringEncoding)!, options: [NSDocumentTypeDocumentAttribute:NSHTMLTextDocumentType,NSCharacterEncodingDocumentAttribute:NSUTF8StringEncoding], documentAttributes: nil, error: nil)!
}
}
extension NSData{
var htmlString:String {
return NSAttributedString(data: self, options: [NSDocumentTypeDocumentAttribute:NSHTMLTextDocumentType,NSCharacterEncodingDocumentAttribute:NSUTF8StringEncoding], documentAttributes: nil, error: nil)!.string
}
}
let result = html2String("\(busDescriptio)") // Business Description HTML
let yourAttributedText = "<style type=\"text/css\">#busDescriptio{color:white;align-content:left;}#green{color:#0F0}#blue{color: #00F; font-weight: Bold; font-size: 32}</style><span id=\"busDescriptio\" >\(result),</span><span id=\"green\" > Green </span><span id=\"blue\">and Blue</span>".html2NSAttributedString
// Create UITextView
var textView = UITextView(frame: CGRectMake(0, 95.0, screenWidth-10, 300.0))
textView.attributedText = yourAttributedText
textView.backgroundColor = UIColor.clearColor()
textView.font = UIFont.preferredFontForTextStyle(UIFontTextStyleBody)
border.addSubview(textView)
func html2String(html:String) -> String {
return NSAttributedString(data: html.dataUsingEncoding(NSUTF8StringEncoding)!, options:[NSDocumentTypeDocumentAttribute:NSHTMLTextDocumentType,NSCharacterEncodingDocumentAttribute:NSUTF8StringEncoding], documentAttributes: nil, error: nil)!.string
}
I think you're stuck thinking about HTML. Once you have created an NSAttributedString or, more accurately, an NSMutableAttributedString from the HTML, you can just apply your own attributes. At that point, the HTML is no longer relevant. You certainly shouldn't try to achieve formatting by manipulating the HTML before converting it into an attributed string.
You don't say what "style" or attributes you want to change, so it's hard to give you an example, but just set or remove whatever attributes you want. You have the power to completely override whatever styling was introduced by the CSS in the HTML.
For example, do [someMutableAttributedString addAttribute:NSForegroundColorAttributeName value:[UIColor blueColor] range:NSMakeRange(0, someMutableAttributedString.length)] to change the color to blue.
Here's some Objective-C code which works for me on OS X:
NSString* html = #"<style type=\"text/css\">#busDescriptio{color:white;align-content:left;}#green{color:#0F0}#blue{color: #00F; font-weight: Bold; font-size: 32}</style><span id=\"busDescriptio\" ><p><span style=\"color:rgb(0, 0, 0); font-family:verdana,arial,tahoma; font-size:12px\">Baxter Eye Care has been serving The Woodlands with quality eye care and personal friendly service since 1981. Dr. Baxter, Dr. Daniels and Dr. Shosa are dedicated to your eye health and vision needs.</span></p>,</span><span id=\"green\" > Green </span><span id=\"blue\">and Blue</span>";
NSData* data = [html dataUsingEncoding:NSUTF8StringEncoding];
NSMutableAttributedString* str = [[NSMutableAttributedString alloc] initWithData:data
options:#{ NSCharacterEncodingDocumentOption: #(NSUTF8StringEncoding),
NSDocumentTypeDocumentOption: NSHTMLTextDocumentType }
documentAttributes:NULL
error:NULL];
[str addAttribute:NSForegroundColorAttributeName value:[NSColor redColor] range:NSMakeRange(0, str.length)];
self.label.attributedStringValue = str;
I don't work in Swift, but here's a pass at a simple translation:
let html = "<style type=\"text/css\">#busDescriptio{color:white;align-content:left;}#green{color:#0F0}#blue{color: #00F; font-weight: Bold; font-size: 32}</style><span id=\"busDescriptio\" ><p><span style=\"color:rgb(0, 0, 0); font-family:verdana,arial,tahoma; font-size:12px\">Baxter Eye Care has been serving The Woodlands with quality eye care and personal friendly service since 1981. Dr. Baxter, Dr. Daniels and Dr. Shosa are dedicated to your eye health and vision needs.</span></p>,</span><span id=\"green\" > Green </span><span id=\"blue\">and Blue</span>"
let data = html.dataUsingEncoding(NSUTF8StringEncoding)!
var str = NSMutableAttributedString(data:data,
options:[ NSCharacterEncodingDocumentOption: NSUTF8StringEncoding,
NSDocumentTypeDocumentOption: NSHTMLTextDocumentType ],
documentAttributes:nil,
error:nil)
str.addAttribute(NSForegroundColorAttributeName, value:NSColor.redColor(), range:NSMakeRange(0, str.length))
self.label.attributedStringValue = str;
So, the code starts with HTML code in a string. It creates an NSMutableAttributedString from that. Then it changes the foreground color, effectively replacing the color resulting from the HTML. Finally, it sets the attributed string as the content of an NSTextField label. For iOS, you could use a UILabel or UITextView or whatever.
In the code you put in your question, there are some things that are troublesome. It's not clear what busDescription is. Is it a string containing HTML code?
Is there a reason that you're interpolating it into a string to pass it to html2String()? That is, why this:
let result = html2String("\(busDescriptio)")
and not this:
let result = html2String(busDescriptio)
?
It seems that html2String() interprets HTML into an attributed string and then just extracts the plain text from that. Why are you doing that?
You are then interpolating that plain text into another block of HTML code. Again, why are you doing that? If you want to apply colors, fonts, etc. to the plain text string, just build an attributed string directly from that plain text string — no HTML involved — and apply the desired attributes.
Or, start from the original busDescriptio, make a mutable attributed string from that HTML code, and apply whatever attributes you like to that.
For example, here's another example:
NSString* busDescriptio = #"<p><span style=\"color:rgb(0, 0, 0); font-family:verdana,arial,tahoma; font-size:12px\">Baxter Eye Care has been serving The Woodlands with quality eye care and personal friendly service since 1981. Dr. Baxter, Dr. Daniels and Dr. Shosa are dedicated to your eye health and vision needs.</span></p>";
NSData* data = [busDescriptio dataUsingEncoding:NSUTF8StringEncoding];
NSMutableAttributedString* foo = [[NSMutableAttributedString alloc] initWithData:data
options:#{ NSCharacterEncodingDocumentOption: #(NSUTF8StringEncoding),
NSDocumentTypeDocumentOption: NSHTMLTextDocumentType }
documentAttributes:NULL
error:NULL];
[str addAttribute:NSFontAttributeName value:[NSFont fontWithName:#"Verdana" size:12] range:NSMakeRange(0, str.length)];
Basically, although your initial input is HTML code, you build a mutable attributed string from that and then don't work in HTML from that point on. Just apply and/or remove attributes from the attributed string, as desired. You can also build separate attributed strings, like your green or blue text in your example, and append those to the mutable one.
Okay so using what Ken Thomases wrote I was able to make it work! After looking at his code and seeing what I did wrong I was able to make it work. Here it is in Swift code just in case anyone has the same problem I had. I'm still having trouble with some images but ideally everything from font color, size, height, alignments and background work! Thanks
// busDescriptio is being occupied by a string with html and css scripting
var data: NSData = busDescriptio.dataUsingEncoding(NSUTF8StringEncoding)!
var foo: NSMutableAttributedString = NSMutableAttributedString(data: data,
options: [NSDocumentTypeDocumentAttribute:NSHTMLTextDocumentType,NSCharacterEncodingDocumentAttribute:NSUTF8StringEncoding],
documentAttributes:nil,
error:nil)!
var paragraph = NSMutableParagraphStyle()
paragraph.alignment = NSTextAlignment.Left
foo.addAttribute(NSFontAttributeName, value: UIFont(name: "Arial", size:12)!, range:NSMakeRange(0, foo.length))
foo.addAttribute(NSForegroundColorAttributeName, value: UIColor.whiteColor(), range: NSRange(location:0,length: foo.length))
foo.addAttribute(NSBackgroundColorAttributeName, value: UIColor.clearColor(), range: NSRange(location: 0, length: foo.length))
foo.addAttribute(NSParagraphStyleAttributeName, value:paragraph, range:NSMakeRange(0, foo.length))

Using MMMarkdown, only system font will show bold or italicized text

I'm using MMMarkdown and when I apply no font to UILabel or UITextView (I have to keep UITextView so TTTAttributedLabel won't do), all of markdown works. When I give the label or textview a font, I only get markdown hyperlinks to work. I tried switching to the AttributedMarkdown library but hyperlinks don't work at all with that one.
In my Markdown Class:
class Markdown: NSObject {
func markdownString(stringForVideoDescription:NSString) -> NSMutableAttributedString {
var options = [NSDocumentTypeDocumentAttribute:NSHTMLTextDocumentType]
var error:NSError?
var markdown:NSString = stringForVideoDescription
var html:NSString = MMMarkdown.HTMLStringWithMarkdown(markdown, error: &error)
var markdownAttributedString:NSMutableAttributedString = NSMutableAttributedString(data: html.dataUsingEncoding(NSUTF32StringEncoding)!, options: options, documentAttributes: nil, error: &error)!
if let font: UIFont = UIFont(name: "Marion-Regular", size: 14) {
markdownAttributedString.addAttributes([NSUnderlineStyleAttributeName:NSUnderlineStyleAttributeName], range: NSMakeRange(0, markdownAttributedString.length))
}
println(html) // used to see that markdown is in fact working
return markdownAttributedString
}
In my view, I'm actually pulling from json api but I replace to test with:
let bodyText = "\*This* sample \[I'm an inline-style link](https://www.google.com)"
myTextView.attributedText = Markdown().markdownString(bodyText)
Do I need to set up css to specify font for each bold, italicized text? Any help is greatly appreciated as my designers don't want to use the default font of Times New Roman.

How to make particular word colored : coming from localized string file of iOS

I would like to make particular word colored like this :
Text in English :-
Same place text in French :-
These text are came from localized string file. And I found solution with the string range property NSMakeRange(0,3) for attributed text from here. This I don't want since text will differ for Localized language string. FYI, I placed text in UITextView.
So how can I achieve this by simple way? Is there any solution that can fix problem in Localized string file itself.
I know this answer is a few years late, but I solved the problem by allowing HTML in my localizable strings. For example:
"emergency" = "This is a test of the <span style=\"color:red\">emergency</span> broadcast system.";
Of course, this alone won't solve the problem, because the localizable string files in IOS don't natively support any sort of HTML/XML annotation. So, you need to process the HTML yourself when you extract the string in your swift code. Here is how I did it:
// Get the localized string
let localized = NSLocalizedString("emergency", comment: "")
// Prepend an html header to the string select the primary font and color.
// The settings on the UITextView or UILabel will be ignored, so you need to do this
let htmlString = "<span style=\"color:yellow;font-size:24px;font-family:-apple-system\">" + localized
// perform the magic to turn the html string into an NSAttributedString
let data = NSString(string: htmlString).data(using: String.Encoding.utf8.rawValue)
do {
let attributedString = try NSAttributedString(data: data!,
options: [
.documentType: NSAttributedString.DocumentType.html,
.characterEncoding: String.Encoding.utf8.rawValue],
documentAttributes: nil)
// Show the NSAttributedString in your help UITextView (or anywhere else)
help.attributedText = attributedString
} catch {
print("There was a problem")
}
This example gives you yellow, 24-point, apple system font text. The localizable string marked the word "emergency" as red, and it will be displayed in red in the final display.
Below snippet might be used for achieving yourrequirement
UITextView *textView = //YourTextView
NSMutableAttributedString *attributedText = [[NSMutableAttributedString alloc] initWithAttributedString: textView.attributedText];
[attributedText addAttribute:NSForegroundColorAttributeName
value:[UIColor redColor]
range:[textView.text rangeOfString:blueString]];
[attributedText addAttribute:NSForegroundColorAttributeName
value:[UIColor blueColor]
range:[textView.text rangeOfString:redString]];
[textView setAttributedText: attributedText];

Resources