Как отображать интерактивные ссылки в UITextView

Я пытаюсь отобразить атрибутированную строку в UITextview с помощью ссылок с возможностью обращения. Я создал простой тестовый проект, чтобы увидеть, где я ошибаюсь и все еще не могу понять. Я попытался включить взаимодействие с пользователем и установил метод делегирования shouldInteractWithURLs, но он все еще не работает. Здесь мой код (для контроллера вида, который содержит только текстовое представление)

  @IBOutlet weak var textView: UITextView!

override func viewDidLoad() {
    super.viewDidLoad()
    // Do any additional setup after loading the view, typically from a nib.
    let string = "Google"
    let linkString = NSMutableAttributedString(string: string)
    linkString.addAttribute(NSLinkAttributeName, value: NSURL(string: "https://www.google.com")!, range: NSMakeRange(0, string.characters.count))
    linkString.addAttribute(NSFontAttributeName, value: UIFont(name: "HelveticaNeue", size: 25.0)!, range: NSMakeRange(0, string.characters.count))
    textView.attributedText = linkString
    textView.delegate = self
    textView.selectable = true
    textView.userInteractionEnabled = true
}

И вот методы делегата, которые я реализовал:

func textViewShouldBeginEditing(textView: UITextView) -> Bool {
    return false
}

func textView(textView: UITextView, shouldInteractWithURL URL: NSURL, inRange characterRange: NSRange) -> Bool {
    return true
}

Это еще не работает. Я искал эту тему, и ничего не помогло. Большое спасибо заранее.

Ответ 1

Просто выберите UITextView в своем раскадровке и перейдите в "Показать инспектор атрибутов" и выберите selectable и links. Как показано ниже. Убедитесь, что Editable не установлен.

введите описание изображения здесь

Ответ 2

Swift 3 iOS 10: Здесь доступен Clickable расширенный UITextView, который автоматически обнаруживает веб-сайты внутри текстового поля, пока ссылка начинается с www., например: www. exmaple.com, если он существует в любом месте текста, будет доступен для кликов. Здесь класс:

import Foundation
import UIKit




public class ClickableTextView:UITextView{



    var tap:UITapGestureRecognizer!
    override public init(frame: CGRect, textContainer: NSTextContainer?) {
        super.init(frame: frame, textContainer: textContainer)
        print("init")
        setup()
    }
    required public init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        setup()
    }


    func setup(){

        // Add tap gesture recognizer to Text View
        tap = UITapGestureRecognizer(target: self, action: #selector(self.myMethodToHandleTap(sender:)))
        //        tap.delegate = self
        self.addGestureRecognizer(tap)
    }

    func myMethodToHandleTap(sender: UITapGestureRecognizer){

        let myTextView = sender.view as! UITextView
        let layoutManager = myTextView.layoutManager

        // location of tap in myTextView coordinates and taking the inset into account
        var location = sender.location(in: myTextView)
        location.x -= myTextView.textContainerInset.left;
        location.y -= myTextView.textContainerInset.top;


        // character index at tap location
        let characterIndex = layoutManager.characterIndex(for: location, in: myTextView.textContainer, fractionOfDistanceBetweenInsertionPoints: nil)

        // if index is valid then do something.
        if characterIndex < myTextView.textStorage.length {

            let orgString = myTextView.attributedText.string


            //Find the WWW
            var didFind = false
            var count:Int = characterIndex
            while(count > 2 && didFind == false){

                let myRange = NSRange(location: count-1, length: 2)
                let substring = (orgString as NSString).substring(with: myRange)

//                print(substring,count)

                if substring == " w" || (substring  == "w." && count == 3){
                    didFind = true
//                    print("Did find",count)

                    var count2 = count
                    while(count2 < orgString.characters.count){

                        let myRange = NSRange(location: count2 - 1, length: 2)
                        let substring = (orgString as NSString).substring(with: myRange)

//                        print("Did 2",count2,substring)
                        count2 += 1


                        //If it was at the end of textView
                        if count2  == orgString.characters.count {

                            let length = orgString.characters.count - count
                            let myRange = NSRange(location: count, length: length)

                            let substring = (orgString as NSString).substring(with: myRange)

                            openLink(link: substring)
                            print("It a Link",substring)
                            return
                        }

                        //If it in the middle

                        if substring.hasSuffix(" "){

                            let length =  count2 - count
                            let myRange = NSRange(location: count, length: length)

                            let substring = (orgString as NSString).substring(with: myRange)

                            openLink(link: substring)
                            print("It a Link",substring)

                            return
                        }

                    }

                    return
                }


                if substring.hasPrefix(" "){

                    print("Not a link")
                    return
                }

                count -= 1

            }


        }


    }


    func openLink(link:String){

        if let checkURL = URL(string: "http://\(link.replacingOccurrences(of: " ", with: ""))") {
            if UIApplication.shared.canOpenURL(checkURL) {
                UIApplication.shared.open(checkURL, options: [:], completionHandler: nil)

                print("url successfully opened")
            }
        } else {
            print("invalid url")
        }
    }


    public override func didMoveToWindow() {
        if self.window == nil{
            self.removeGestureRecognizer(tap)
            print("ClickableTextView View removed from")
        }
    }
}