Make the text hyperlink or clickable in UITextView - ios

I am having the UITextView and displaying text in it from three tags(message, titleUrl and url). What i need is that i want to make the text of "titleUrl" clickable to open the value of "url" in web view. I managed to open the link directly from url, but i need to open the link by clicking "titleUrl". I have tried to achieve the following from this code.
[self buildAgreeTextViewFromString:NSLocalizedString(#"I agree to the #<ts>terms of service# and #<pp>privacy policy#",
#"PLEASE NOTE: please translate \"terms of service\" and \"privacy policy\" as well, and leave the #<ts># and #<pp># around your translations just as in the English version of this message.")];
But i am not getting in this how to modify this to achieve the functionality. I want to enter the value have in string, don't have the static text to enter. Can anyone guide me to handle this?
Update:
NSString *message = [NSString stringWithFormat:#"%#\n ", tempStr1];
NSString *message1 = [NSString stringWithFormat:#"\n#<pp>%##", titlStr1];
NSString *localizedString = NSLocalizedString(message1, nil);
NSRange ppRange = [localizedString rangeOfString:NSLocalizedString(message1, nil) options:NSCaseInsensitiveSearch];
NSURL *ppURL = [NSURL URLWithString:strUrl];
NSDictionary *attribute1 = #{NSForegroundColorAttributeName: [UIColor whiteColor],
NSFontAttributeName: [UIFont fontWithName:#"HelveticaNeue" size:15.0],
};
NSMutableAttributedString *newAttString = [[NSMutableAttributedString alloc] initWithString:message attributes:attribute1];
//
NSMutableAttributedString *finalMessage = [[NSMutableAttributedString alloc] initWithString:localizedString];
[finalMessage beginEditing];
[finalMessage addAttributes:attribute1 range:ppRange];
[finalMessage addAttribute:NSLinkAttributeName value:ppURL range:ppRange];
[finalMessage endEditing];
[newAttString appendAttributedString:finalMessage];
self.txtView.attributedText = newAttString;

This is as simple as using an NSMutableAttributedString. Note: This is not the only way, this can be done with searching for ranges etc, this is just a simple implementation to get you in the right direction since you do have the static message, because your localizing all of them, which means you have the static english form of it.
NSString *tosString = #"Terms of Service";
NSString *ppString = #"Privacy Policy";
NSString *message = [NSString stringWithFormat:#"I agree to the #<ts>%## and #<pp>%##", tosString, ppString];
NSString *localizedString = NSLocalizedString(message, nil);
NSRange tosRange = [localizedString rangeOfString:NSLocalizedString(tosString, nil) options:NSCaseInsensitiveSearch];
NSRange ppRange = [localizedString rangeOfString:NSLocalizedString(ppString, nil) options:NSCaseInsensitiveSearch];
NSURL *tosURL = [NSURL URLWithString:#"http://toslink.com"];
NSURL *ppURL = [NSURL URLWithString:#"http://pplink.com"];
NSMutableAttributedString *finalMessage = [[NSMutableAttributedString alloc] initWithString:localizedString];
[finalMessage beginEditing];
[finalMessage addAttribute:NSLinkAttributeName value:tosURL range:tosRange];
[finalMessage addAttribute:NSLinkAttributeName value:ppURL range:ppRange];
[finalMessage endEditing];
self.yourTextView.attributedText = finalMessage;

Swift 3.0
in your view did load...
let tosString = "Terms of Service"
let ppString = "Privacy Policy"
let message = "By logging in, you agree to our (tosString) and that you have read our (ppString)"
let localizedString = NSMutableAttributedString(string: message)
let tosRange = localizedString.mutableString.range(of: tosString)
let ppRange = localizedString.mutableString.range(of: ppString)
let tosURL = URL(string: "http://toslink.com")!
let ppURL = URL(string: "http://pplink.com")!
localizedString.addAttribute(NSLinkAttributeName, value: tosURL, range: tosRange)
localizedString.addAttribute(NSLinkAttributeName, value: ppURL, range: ppRange)
demoTextView.delegate = self
demoTextView.isSelectable = true
demoTextView.isUserInteractionEnabled = true
localizedString.endEditing()
self.demoTextView.attributedText = localizedString
and using textview delegate method
func textView(_ textView: UITextView, shouldInteractWith URL: URL, in characterRange: NSRange) -> Bool {
// Handle your Control
return true
}

Look into using an attributed string with NSLinkAttributeName.

Related

open a web link from different text in a text view

I have an iOS app in which the text from a text view is too long to fit. So I am trying to link the web address to the text in the textView.
Here is what I have.
NSURL *URL = [NSURL URLWithString:#"azgovernor.gov/engage/form/contact-governor-ducey"];
NSMutableAttributedString *str = [[NSMutableAttributedString alloc] initWithString:#"Email Governor"];
[str addAttribute: NSLinkAttributeName value:URL range: NSMakeRange(0, str.length)];
govemail.attributedText = str;
The Email Governor shows up in the TextView as hyperlink(blue link) and when I touch it, it reacts.
However, the link doesn't respond and I get this message:
Could not find any actions for URL azgovernor.gov/engage/form/contact-governor-ducey without any result.
If I put this address into Safari it opens the page fine. What do I need to do to make this work?
try this:
NSAttributedString *str = [[NSAttributedString alloc] initWithString:#"http://azgovernor.gov/engage/form/contact-governor-ducey"];
govemail.dataDetectorTypes = UIDataDetectorTypeLink;
govemail.editable = NO;
govemail.attributedText = str;

How to just add underline below the second line of text in a Bar Button Item?

This is what I want to achieve:
I'm thinking about having two separate attributed strings and combine them together. Not sure if this is the only way?
UPDATE
The button displays "(null)" if using setAttributedTitle. It can display the right string with no attributes if using setTitle.
Still cannot display in the intended way. Any idea?
// Set current bar button attributes
NSMutableAttributedString *currentBarAttributedString = [[NSMutableAttributedString alloc] init];
[currentBarAttributedString appendAttributedString:[[NSAttributedString alloc] initWithString:#"REQUEST\n"
attributes:#{NSUnderlineStyleAttributeName: #(NSUnderlineStyleNone)}]];
[currentBarAttributedString appendAttributedString:[[NSAttributedString alloc] initWithString:#"EQUIPMENT"
attributes:#{NSUnderlineStyleAttributeName: #(NSUnderlineStyleSingle)}]];
// Initialize buttons and set titles
UIButton *button1 = [UIButton buttonWithType:UIButtonTypeCustom];
[button1 setAttributedTitle:currentBarAttributedString forState:UIControlStateNormal];
// [button1 setTitle:[currentBarAttributedString string] forState:UIControlStateNormal];
To add border to text or to change color.here is sample code which is used.
use This code in
- (void)viewDidLoad {
[super viewDidLoad];
NSString *strFirst = #"Request Equipment";
NSString *strSecond = #"Active Rentals";
NSMutableAttributedString *attributedString = [[NSMutableAttributedString alloc] init];
[attributedString appendAttributedString:[[NSAttributedString alloc] initWithString:strFirst
attributes:#{NSUnderlineStyleAttributeName: #(NSUnderlineStyleSingle),
NSForegroundColorAttributeName:[UIColor yellowColor]}]];
[attributedString appendAttributedString:[[NSAttributedString alloc] initWithString:strSecond
attributes:#{NSUnderlineStyleAttributeName: #(NSUnderlineStyleNone),NSForegroundColorAttributeName:[UIColor whiteColor]}]];
//To use attribute string in button
[self.btnAttributeString setAttributedTitle:attributedString forState:UIControlStateNormal];
}
OutPut is
Please check this and let me know any issue.
Just create a NSAttributedString and format it as required
NSString *alertString = #"All heroes do not wear capes.";
NSMutableParagraphStyle* paragraphStyle = [[NSMutableParagraphStyle alloc] init];
paragraphStyle.alignment = NSTextAlignmentLeft;
NSDictionary *attrs = #{
NSParagraphStyleAttributeName: paragraphStyle,
//provide a nsdict here with attributes you want to apply to the whole of the string.
};
NSDictionary *subAttrs = #{
NSParagraphStyleAttributeName: paragraphStyle,
//Here provide attributes for the not underlined part of the string.
};
NSDictionary *subAttrs2 = #{
NSParagraphStyleAttributeName: paragraphStyle,
//Here provide attributes for the underlined part of the string
};
//Set the range of the sub attributes.
const NSRange range = NSMakeRange(0,3);
const NSRange range2 = NSMakeRange(5,4);
NSMutableAttributedString *attributedText =
[[NSMutableAttributedString alloc] initWithString:alertString
attributes:attrs];
[attributedText setAttributes:subAttrs range:range];
[attributedText setAttributes:subAttrs2 range:range2];
Now set this attributed string as your attributed title
class UnderlinedLabel: UILabel {
override var text: String! {
didSet {
let textRange = NSMakeRange(0, count(text))
let textRange = NSMakeRange(0, text.characters.count)
let attributedText = NSMutableAttributedString(string: text)
attributedText.addAttribute(NSUnderlineStyleAttributeName , value:NSUnderlineStyle.StyleSingle.rawValue, range: textRange)
// Add other attributes if needed
self.attributedText = attributedText
}
}
}

Add a nsstring at the end of attributed string in textview iOS

I have a text like "Hello There" which will be a attributed string with red color. Then at the end of that attributed string I want to append a nsstring 'Who are you?' But whenever I append a nsstring, the whole string becomes normal nsstring and the property of the attributed string is being removed. My attempt so far:
NSMutableAttributedString *attributeString = [[NSMutableAttributedString alloc] initWithString:#"Hello There"];
[attributeString addAttribute:NSForegroundColorAttributeName value:[UIColor redColor] range:NSMakeRange(0,[attributeString length])];
NSMutableAttributedString *previousAttrString = [[NSMutableAttributedString alloc] initWithString:messageTextView.text];
[previousAttrString insertAttributedString: attributeString atIndex:location];
messageTextView.attributedText = previousAttrString;
messageTextView.font = [UIFont fontWithName:#"Helvetica" size:15];
NSString *messageWithContact = [NSString stringWithFormat: #"%# %#", messageTextView.text, #"Who are you?"];
messageTextView.text=messageWithContact;
What I did wrong? Please help me.
Replace the bottom lines
NSString *messageWithContact = [NSString stringWithFormat: #"%# %#", messageTextView.text, #"Who are you?"];
messageTextView.text=messageWithContact;
with
NSMutableAttributedString *newString = messageTextView.attibutedText;
[newString appendAttributedString: [[NSAttributedString alloc] initWithString: #"Who are you?"];
messageTextView.attibutedText = newString;

Easiest way to style the text of an UILabel in iOS7/iOS8

I'm learning objective c a little bit to write an iPad app. I've mostly done some html5/php projects and learned some python at university. But one thing that really blows my mind is how hard it is to just style some text in an objective C label.
Maybe I'm coming from a lazy markdown generation, but really, if I want to let an UILabel look like:
Objective: Construct an equilateral triangle from the line segment AB.
In markdown this is as simple as:
**Objective:** Construct an *equilateral* triangle from the line segment AB.
Is there really no pain free objective C way to do this ? All the tutorials I read really wanted me to write like 15 lines of code. For something as simple as this.
So my question is, what is the easiest way to do this, if you have a lot of styling to do in your app ? Will styling text become more natural with swift in iOS8 ?
You can use NSAttributedString's data:options:documentAttributes:error: initializer (first available in iOS 7.0 SDK).
import UIKit
let htmlString = "<b>Objective</b>: Construct an <i>equilateral</i> triangle from the line segment AB."
let htmlData = htmlString.dataUsingEncoding(NSUTF8StringEncoding)
let options = [NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType]
var error : NSError? = nil
let attributedString = NSAttributedString(data: htmlData, options: options, documentAttributes: nil, error: &error)
if error == nil {
// we're good
}
Note: You might also want to include NSDefaultAttributesDocumentAttribute option in the options dictionary to provide additional global styling (such as telling not to use Times New Roman).
Take a look into NSAttributedString UIKit Additions Reference for more information.
I faced similar frustrations while trying to use attributed text in Xcode, so I feel your pain. You can definitely use multiple NSMutableAttributedtext's to get the job done, but this is very rigid.
UIFont *normalFont = [UIFont fontWithName:#"..." size:20];
UIFont *boldFont = [UIFont fontWithName:#"..." size:20];
UIFont *italicizedFont = [UIFont fontWithName:#"..." size:20];
NSMutableAttributedString *total = [[NSMutableAttributedString alloc]init];
NSAttributedString *string1 = [[NSAttributedString alloc] initWithString:[NSString stringWithFormat:#"Objective"] attributes:#{NSFontAttributeName:boldFont}];
NSAttributedString *string2 = [[NSAttributedString alloc] initWithString:[NSString stringWithFormat:#": Construct an "] attributes:#{NSFontAttributeName:normalFont}];
NSAttributedString *string3 = [[NSAttributedString alloc] initWithString:[NSString stringWithFormat:#"equilateral "] attributes:#{NSFontAttributeName:italicizedFont}];
NSAttributedString *string4 = [[NSAttributedString alloc] initWithString:[NSString stringWithFormat:#"triangle from the line segment AB."] attributes:#{NSFontAttributeName:normalFont}];
[total appendAttributedString:string1];
[total appendAttributedString:string2];
[total appendAttributedString:string3];
[total appendAttributedString:string4];
[self.someLabel setAttributedText: total];
Another option is to use NSRegularExpression. While this will require more lines of code, it is a more fluid way of bolding, changing color, etc from an entire string at once. For your purposes however, using the appendAttributedString will be the shortest way with a label.
UIFont *normalFont = [UIFont fontWithName:#"..." size:20];
UIFont *boldFont = [UIFont fontWithFamilyName:#"..." size: 20];
UIFont *italicizedFont = [UIFont fontWithFamilyName:#"..." size: 20];
NSMutableAttributedString *attributedString = [[NSMutableAttributedString alloc] initWithString:[NSString stringWithFormat: #"Objective: Construct an equilateral triangle from the line segment AB."] attributes:#{NSFontAttributeName:normalFont}];
NSError *regexError;
NSRegularExpression *regex1 = [NSRegularExpression regularExpressionWithPattern:#"Objective"
options:NSRegularExpressionCaseInsensitive error:&regexError];
NSRegularExpression *regex2 = [NSRegularExpression regularExpressionWithPattern:#"equilateral"
options:NSRegularExpressionCaseInsensitive error:&regexError];
if (!regexError)
{
NSArray *matches1 = [regex1 matchesInString:[attributedString string]
options:0
range:NSMakeRange(0, [[attributedString string] length])];
NSArray *matches2 = [regex2 matchesInString:[attributedString string]
options:0
range:NSMakeRange(0, [[attributedString string] length])];
for (NSTextCheckingResult *aMatch in matches1)
{
NSRange matchRange = [aMatch range];
[attributedString setAttributes:#{NSFontAttributeName:boldFont}
range:matchRange];
}
for (NSTextCheckingResult *aMatch in matches2)
{
NSRange matchRange = [aMatch range];
[attributedString setAttributes:#{NSFontAttributeName:italicizedFont}
range:matchRange];
}
[self.someLabel setAttributedText: attributedString];
Just to update the akashivskyy’s answer (+1) with contemporary Swift syntax:
guard let data = htmlString.data(using: .utf8) else { return }
do {
let attributedString = try NSAttributedString(
data: data,
options: [.documentType: NSAttributedString.DocumentType.html],
documentAttributes: nil
)
...
} catch {
print(error)
}

Change attributes of substrings in a NSAttributedString

This question may be a duplicate of this one. But the answers don't work for me and I want to be more specific.
I have a NSString, but I need a NS(Mutable)AttributedString and some of the words in this string should be given a different color. I tried this:
NSString *text = #"This is the text and i want to replace something";
NSDictionary *attributes = # {NSForegroundColorAttributeName : [UIColor redColor]};
NSMutableAttributedString *subString = [[NSMutableAttributedString alloc] initWithString:#"AND" attributes:attributes];
NSMutableAttributedString *newText = [[NSMutableAttributedString alloc] initWithString:text];
newText = [[newText mutableString] stringByReplacingOccurrencesOfString:#"and" withString:[subString mutableString]];
The "and" should be uppercase an red.
The documentation says that mutableString keeps the attribute mappings. But with my replacing-thing, I have no more attributedString on the right side of the assignment (in the last line of my code-snippet).
How can I get what I want? ;)
#Hyperlord's answer will work, but only if there is one occurence of the word "and" in the input string. Anyway, what I would do is use NSString's stringByReplacingOccurrencesOfString: initially to change every "and" to an "AND", then use a little regex to detect matches in attributed string, and apply NSForegroundColorAttributeName at that range. Here's an example:
NSString *initial = #"This is the text and i want to replace something and stuff and stuff";
NSString *text = [initial stringByReplacingOccurrencesOfString:#"and" withString:#"AND"];
NSMutableAttributedString *mutableAttributedString = [[NSMutableAttributedString alloc] initWithString:text];
NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:#"(AND)" options:kNilOptions error:nil];
NSRange range = NSMakeRange(0,text.length);
[regex enumerateMatchesInString:text options:kNilOptions range:range usingBlock:^(NSTextCheckingResult *result, NSMatchingFlags flags, BOOL *stop) {
NSRange subStringRange = [result rangeAtIndex:1];
[mutableAttributedString addAttribute:NSForegroundColorAttributeName value:[UIColor redColor] range:subStringRange];
}];
And finally, just apply the attributed string to your label.
[myLabel setAttributedText:mutableAttributedString];
I think you should create a NSMutableAttributedString using the existing NSString and then add the style attributes with the appropriate NSRange in order to colorize the parts you want to emphasize for example:
NSString *text = #"This is the text and i want to replace something";
NSMutableAttributedString *mutable = [[NSMutableAttributedString alloc] initWithString:text];
[mutable addAttribute: NSForegroundColorAttributeName value:[UIColor redColor] range:[text rangeOfString:#"and"]];
Be aware: this is just from my head and not tested at all ;-)
Please try this code in Swift 2
var someStr = "This is the text and i want to replace something"
someStr.replaceRange(someStr.rangeOfString("and")!, with: "AND")
let attributeStr = NSMutableAttributedString(string: someStr)
attributeStr.setAttributes([NSForegroundColorAttributeName: UIColor.yellowColor()], range: NSMakeRange(17, 3) )
testLbl.attributedText = attributeStr
Here's another implementation (in Swift) that's helpful if you're doing some more complex manipulations (such as adding/deleting characters) with your attributed string:
let text = "This is the text and i want to replace something"
let mutAttrStr = NSMutableAttributedString(string: text)
let pattern = "\\band\\b"
let regex = NSRegularExpression(pattern: pattern, options: .allZeros, error: nil)
while let result = regex!.firstMatchInString(mutAttrStr.string, options: .allZeros, range:NSMakeRange(0, count(mutAttrStr.string)) {
let substring = NSMutableAttributedString(attributedString: mutAttrStr.attributedSubstringFromRange(result.range))
// manipulate substring attributes here
substring.addAttribute(NSForegroundColorAttributeName, value: UIColor.redColor(), range NSMakeRange(0, count(substring.string))
mutAttrStr.replaceCharactersInRange(result.range, withAttributedString: substring)
}
Your final attributed string should be:
let finalAttrStr = mutAttrStr.copy() as! NSAttributedString

Resources