How can I make a clickable link in an NSAttributed

2019-01-01 06:50发布

It's trivial to make hyperlinks clickable in a UITextView. You just set the "detect links" checkbox on the view in IB, and it detects HTTP links and turns them into hyperlinks.

However, that still means that what the user sees is the "raw" link. RTF files and HTML both allow you to set up a user-readable string with a link "behind" it.

It's easy to install attributed text into a text view (or a UILabel or UITextField, for that matter.) However, when that attributed text includes a link, it is not clickable.

Is there a way to make user-readable text clickable in a UITextView, UILabel or UITextField?

The markup is different on SO, but here is the general idea. What I want is text like this:

This morph was generated with Face Dancer, Click to view in the app store.

The only thing I can get is this:

This morph was generated with Face Dancer, Click on http://example.com/facedancer to view in the app store.

21条回答
笑指拈花
2楼-- · 2019-01-01 07:06
NSMutableAttributedString *attributedString = [[NSMutableAttributedString alloc] initWithString:strSomeTextWithLinks];

NSDictionary *linkAttributes = @{NSForegroundColorAttributeName: [UIColor redColor],   
                                 NSUnderlineColorAttributeName: [UIColor blueColor],
                                 NSUnderlineStyleAttributeName: @(NSUnderlinePatternSolid)};

customTextView.linkTextAttributes = linkAttributes; // customizes the appearance of links
textView.attributedText = attributedString;

KEY POINTS:

  • Make sure that you enable "Selectable" behavior of the UITextView in XIB.
  • Make sure that you disable "Editable" behavior of the UITextView in XIB.
查看更多
公子世无双
3楼-- · 2019-01-01 07:09

Swift 3 example to detect actions on attributed text taps

https://stackoverflow.com/a/44226491/5516830

let termsAndConditionsURL = TERMS_CONDITIONS_URL;
let privacyURL            = PRIVACY_URL;

override func viewDidLoad() {
    super.viewDidLoad()

    self.txtView.delegate = self
    let str = "By continuing, you accept the Terms of use and Privacy policy"
    let attributedString = NSMutableAttributedString(string: str)
    var foundRange = attributedString.mutableString.range(of: "Terms of use") //mention the parts of the attributed text you want to tap and get an custom action
    attributedString.addAttribute(NSLinkAttributeName, value: termsAndConditionsURL, range: foundRange)
    foundRange = attributedString.mutableString.range(of: "Privacy policy")
    attributedString.addAttribute(NSLinkAttributeName, value: privacyURL, range: foundRange)
    txtView.attributedText = attributedString
}

func textView(_ textView: UITextView, shouldInteractWith URL: URL, in characterRange: NSRange) -> Bool {
    let storyboard = UIStoryboard(name: "Main", bundle: nil)
    let vc = storyboard.instantiateViewController(withIdentifier: "WebView") as! SKWebViewController

    if (URL.absoluteString == termsAndConditionsURL) {
        vc.strWebURL = TERMS_CONDITIONS_URL
        self.navigationController?.pushViewController(vc, animated: true)
    } else if (URL.absoluteString == privacyURL) {
        vc.strWebURL = PRIVACY_URL
        self.navigationController?.pushViewController(vc, animated: true)
    }
    return false
}

Like wise you can add any action you want with shouldInteractWith URLUITextFieldDelegate method.

Cheers!!

查看更多
大哥的爱人
4楼-- · 2019-01-01 07:11

A quick addition to Duncan C's original description vis-á-vie IB behavior. He writes: "It's trivial to make hyperlinks clickable in a UITextView. You just set the "detect links" checkbox on the view in IB, and it detects http links and turns them into hyperlinks."

My experience (at least in xcode 7) is that you also have to unclick the "Editable" behavior for the urls to be detected & clickable.

查看更多
其实,你不懂
5楼-- · 2019-01-01 07:11

If you want to use the NSLinkAttributeName in a UITextView, then you may consider using the AttributedTextView library. It's a UITextView subclass that makes it very easy to handle these. For more info see: https://github.com/evermeer/AttributedTextView

You can make any part of the text interact like this (where textView1 is a UITextView IBoutlet):

textView1.attributer =
    "1. ".red
    .append("This is the first test. ").green
    .append("Click on ").black
    .append("evict.nl").makeInteract { _ in
        UIApplication.shared.open(URL(string: "http://evict.nl")!, options: [:], completionHandler: { completed in })
    }.underline
    .append(" for testing links. ").black
    .append("Next test").underline.makeInteract { _ in
        print("NEXT")
    }
    .all.font(UIFont(name: "SourceSansPro-Regular", size: 16))
    .setLinkColor(UIColor.purple) 

And for handling hashtags and mentions you can use code like this:

textView1.attributer = "@test: What #hashtags do we have in @evermeer #AtributedTextView library"
    .matchHashtags.underline
    .matchMentions
    .makeInteract { link in
        UIApplication.shared.open(URL(string: "https://twitter.com\(link.replacingOccurrences(of: "@", with: ""))")!, options: [:], completionHandler: { completed in })
    }
查看更多
时光乱了年华
6楼-- · 2019-01-01 07:12

The heart of my question was that I wanted to be able to create clickable links in text views/fields/labels without having to write custom code to manipulate the text and add the links. I wanted it to be data-driven.

I finally figured out how to do it. The issue is that IB doesn't honor embedded links.

Furthermore, the iOS version of NSAttributedString doesn't let you initialize an attributed string from an RTF file. The OS X version of NSAttributedString does have an initializer that takes an RTF file as input.

NSAttributedString conforms to the NSCoding protocol, so you can convert it to/from NSData

I created an OS X command line tool that takes an RTF file as input and outputs a file with the extension .data that contains the NSData from NSCoding. I then put the .data file into my project and add a couple of lines of code that loads the text into the view. The code looks like this (this project was in Swift) :

/*
If we can load a file called "Dates.data" from the bundle and convert it to an attributed string,
install it in the dates field. The contents contain clickable links with custom URLS to select
each date.
*/
if
  let datesPath = NSBundle.mainBundle().pathForResource("Dates", ofType: "data"),
  let datesString = NSKeyedUnarchiver.unarchiveObjectWithFile(datesPath) as? NSAttributedString
{
  datesField.attributedText = datesString
}

For apps that use a lot of formatted text, I create a build rule that tells Xcode that all the .rtf files in a given folder are source and the .data files are the output. Once I do that, I simply add .rtf files to the designated directory, (or edit existing files) and the build process figures out that they are new/updated, runs the command line tool, and copies the files into the app bundle. It works beautifully.

I wrote a blog post that links to a sample (Swift) project demonstrating the technique. You can see it here:

Creating clickable URLs in a UITextField that open in your app

查看更多
余欢
7楼-- · 2019-01-01 07:13

Swift Version :

    // Attributed String for Label
    let plainText = "Apkia"
    let styledText = NSMutableAttributedString(string: plainText)
    // Set Attribuets for Color, HyperLink and Font Size
    let attributes = [NSFontAttributeName: UIFont.systemFontOfSize(14.0), NSLinkAttributeName:NSURL(string: "http://apkia.com/")!, NSForegroundColorAttributeName: UIColor.blueColor()]
    styledText.setAttributes(attributes, range: NSMakeRange(0, plainText.characters.count))
    registerLabel.attributedText = styledText
查看更多
登录 后发表回答