Search code examples
swiftuitableviewurluitextviewuitextviewdelegate

How to detect if a link, inside a UITextView inside a TabelCell has been clicked, Swift


My goal is to log all the links that the user clicks on. The links are embedded in a UITextView inside a table cell, and when a user presses the link, I want it to call a function that prints the url.

I've looked at similar questions such as How to detect if a link, inside a UITextView has been clicked, Swift and How to intercept click on link in UITextView? where people have suggested using the function shouldInteractWithURL, but the function never gets called.

I think I might have set the delegate or the function in the wrong place, and it would be great if somebody could let me know how it should be setup.

Here are the abbreviated code and some screenshots of the page:

class BSPdetailViewController: UIViewController, UITableViewDelegate, UITableViewDataSource, UITextViewDelegate {


    func textView(textView: UITextView!, shouldInteractWithURL URL: NSURL!, inRange characterRange: NSRange) -> Bool {
        print("Link Selected!")
        return true

    }

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {

        let cell = tableView.dequeueReusableCell(withIdentifier: "detailCell", for: indexPath as IndexPath) as! detailCell
        cell.label?.text = ""


        cell.detailLinks.delegate = self
        cell.detailLinks.isUserInteractionEnabled = true // default: true
        cell.detailLinks.isEditable = false // default: true
        cell.detailLinks.isSelectable = true // default: true
        cell.detailLinks.dataDetectorTypes = [.link]

        cell.detailTextLabel?.font = UIFont.fontAwesome(ofSize: 20)
        cell.detailTextLabel?.text = ""
        cell.detailTextLabel?.numberOfLines = 0;


        cell.detailLinks?.text = "links are here"
        var linkString = NSMutableAttributedString(string: "", attributes: [NSFontAttributeName:UIFont.systemFont(ofSize: 22.0)])
        let video =  String.fontAwesomeIcon(code: "fa-video-camera")! + "  "
        let document = String.fontAwesomeIcon(code: "fa-file-text")! + "\n\n"

        for i in 0..<stratList.count {
            var stratURL = stratList[i].lowercased().replacingOccurrences(of: " ", with: "-")

            var docLink = "http://" + stratURL
            var videoLink = "http://" + stratURL

            //setting the url
            var attributedString = NSMutableAttributedString(string: video, attributes: [NSFontAttributeName: UIFont.fontAwesome(ofSize: 22)])
            attributedString.addAttribute(NSLinkAttributeName, value: docLink, range: NSRange(location: 0, length: 1))
            linkString.append(attributedString as NSAttributedString)

            attributedString = NSMutableAttributedString(string: document, attributes: [NSFontAttributeName: UIFont.fontAwesome(ofSize: 22)])
            attributedString.addAttribute(NSLinkAttributeName, value: videoLink, range: NSRange(location: 0, length: 1))
            linkString.append(attributedString as NSAttributedString)


            cell.label?.text = (cell.label?.text)! + "• " + stratList[i] + "\n\n"


            cell.detailLinks?.attributedText = linkString

            //tried tapgesture but it didn't work when I tapped on the links
            //cell.detailLinks.addGestureRecognizer(UITapGestureRecognizer(target: cell.detailLinks, action: #selector(cell.detailLinks.singleTap(tap:))))

            cell.backgroundColor = contentColors[rowNo]
            cell.label?.textColor = UIColor.black
        }


        return cell
    }
}

class detailCell: UITableViewCell
{

    @IBOutlet weak var detailLinks: UITextView!
    @IBOutlet weak var label: UILabel!

}

enter image description here

The resulting table: enter image description here


Solution

  • UITextViewDelegate methods shouldInteractWithURL should be written outside of cellForRowAt not inside. Your standard UITextView setup should look something like this, don't forget the delegate and dataDetectorTypes.

        cell.detailLinks.delegate = self
        detailLinks.isUserInteractionEnabled = true // default: true
        detailLinks.isEditable = false // default: true
        detailLinks.isSelectable = true // default: true
        detailLinks.dataDetectorTypes = [.link]
    

    UITextViewDelegate method shouldInteractWithURL:

    func textView(_ textView: UITextView, shouldInteractWith URL: URL, in characterRange: NSRange, interaction: UITextItemInteraction) -> Bool {
        print("Link Selected!")
        return true
    }