2

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;
iPhone 7
  • 1,731
  • 1
  • 27
  • 63
  • Have you considered using a UIWebView instead of a UITextView? I usually find it easier to just use a UIWebView and write HTML than mess around with attributed strings. The end result is the same to the user. – Aurast Sep 02 '15 at 14:25
  • Ok, how can you make text clickable on UIWebview? – iPhone 7 Sep 02 '15 at 14:28
  • the link text – Aurast Sep 02 '15 at 14:29
  • @rschmidt that's redundant and a lot more code than necessary. – soulshined Sep 02 '15 at 15:39
  • 1
    @soulshined It's not code, it's HTML, it's shorter than using attributed strings, and most developers already knows how to write it. The "code" part is 15 characters. If that is too much, how would you do it with fewer? – Aurast Sep 02 '15 at 16:58
  • @rschmidt the code can be HTML yes, but what about all the other work that goes into creating an `interfaced` `UIWebView` with its `implementation`, along with all the proper delegates. I'm more concerned with user-friendly, and Apple created a user-friendly experience for this circumstance, so why not take advantage of it, instead of 'hacking' it into there, with simple 10 lines of code returning an `NSMutableAttributedString`. See my answer for review – soulshined Sep 02 '15 at 17:25
  • @soulshined You only need delegation if you need to open the link in a different webview, in which case you would need to implement a single protocol method. Using a UIWebView isn't hacking and as far as displaying text with links in it is exactly as user-friendly as a text view. – Aurast Sep 02 '15 at 18:02
  • @rschmidt the point is, instead of directing the OP through a process that they currently aren't using, guide them through the process that they are using. The question is :"make text hyperlink in a UITextView' which can be done and has been done for a long time. No reason to convolute their app structure. Not only does this help the OP. It gives the future question seekers googling this same scenario the correct response – soulshined Sep 02 '15 at 18:05
  • 1
    @soulshined The process that they are using isn't necessarily the one they should be using. In any case, that is what comments are for, and the reason why I didn't post an answer. Depending on the specifics, using UIWebView could easily be simpler to implement and easier to understand than attributed strings. I never told the asker that he should use UIWebView. I suggested he investigate whether he should. – Aurast Sep 02 '15 at 18:12

3 Answers3

8

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;
soulshined
  • 9,612
  • 5
  • 44
  • 79
  • Hey thanks, it works but it is not adjusting in lines, it is in textview but showing only single line of text rest text is offscreen. why so? – iPhone 7 Sep 03 '15 at 06:22
  • And also this is not clickable, not opening url. – iPhone 7 Sep 03 '15 at 07:48
  • You have to make sure you've enabled support for dataTypes @iPhone6 this can be done in storyboard or code. And towards your first comment, that has nothing to do with the answer. It might be a constraint issue or something going on elsewhere with auto layout. – soulshined Sep 03 '15 at 08:34
  • Ok i am adding the update here, what i am doing is passing both the text dynamically that is tappable and that is non tappable. – iPhone 7 Sep 03 '15 at 10:20
  • The problem above is "#welcome to yahoo#". It is showing text like this in UITextView. I don't need that #. And if if i remove this from string it becomes no more clickable. – iPhone 7 Sep 03 '15 at 10:50
  • You have to enable it: `textview.editable = NO; textview.dataDetectorTypes = UIDataDetectorTypeAll;` @iPhone6 – soulshined Sep 03 '15 at 10:51
  • I don't know what the attachments you are referencing please update any details to your question in your question – soulshined Sep 03 '15 at 10:58
  • I just don't understand what you really need @iPhone6 I'm not sure why your appending another string to the same exact string. I'm also not sure why your formatting the first string. I'm sorry but iPhone6 I've helped as much as I can. I offered all the tools and resources you need to make this work. – soulshined Sep 03 '15 at 11:15
4

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 }

Nitin
  • 73
  • 1
  • 4
3

Look into using an attributed string with NSLinkAttributeName.

Douglas Hill
  • 1,537
  • 10
  • 14
  • 1
    Read the documentation or you’ll always be struggling. – Douglas Hill Sep 02 '15 at 14:22
  • Okay, this question might be useful: [UILabel and NSLinkAttributeName: Link is not clickable](http://stackoverflow.com/questions/19854506/uilabel-and-nslinkattributename-link-is-not-clickable) – Douglas Hill Sep 02 '15 at 14:32