Как перехватить ссылку на ссылку в UITextView?

Возможно ли выполнить пользовательское действие, когда пользователь коснется автоопределенной телефонной ссылки в UITextView. Пожалуйста, не советуйте использовать UIWebView.

И, пожалуйста, не просто повторяйте текст из ссылки на классы Apple  - Конечно, я уже прочитал его.

Спасибо.

Ответ 1

Обновление: из ,

- (BOOL)textView:(UITextView *)textView shouldInteractWithURL:(NSURL *)URL inRange:(NSRange)characterRange interaction:(UITextItemInteraction)interaction;

Из и более поздних UITextView имеет метод делегирования:

- (BOOL)textView:(UITextView *)textView shouldInteractWithURL:(NSURL *)URL inRange:(NSRange)characterRange *NS_DEPRECATED_IOS(7_0, 10_0, "Use textView:shouldInteractWithURL:inRange:forInteractionType: instead");*

для перехвата кликов по ссылкам. И это лучший способ сделать это.

Для и ранее хороший способ сделать это - подклассифицировать UIApplication и перезаписать UIApplication адрес -(BOOL)openURL:(NSURL *)url

@interface MyApplication : UIApplication {

}

@end

@implementation MyApplication


-(BOOL)openURL:(NSURL *)url{
    if  ([self.delegate openURL:url])
         return YES;
    else
         return [super openURL:url];
}
@end

Вам нужно будет реализовать openURL: в вашем openURL:.

Теперь, чтобы запустить приложение с вашим новым подклассом UIApplication, найдите файл main.m в своем проекте. В этом маленьком файле, который загружает ваше приложение, обычно есть такая строка:

int retVal = UIApplicationMain(argc, argv, nil, nil);

Третий параметр - это имя класса для вашего приложения. Итак, заменив эту строку на:

int retVal = UIApplicationMain(argc, argv, @"MyApplication", nil);

Это помогло мне.

Ответ 2

В iOS 7 или более поздней версии

Вы можете использовать следующий делегат UITextView. Метод:

- (BOOL)textView:(UITextView *)textView shouldInteractWithURL:(NSURL *)URL inRange:(NSRange)characterRange

Текстовое представление вызывает этот метод, если пользователь нажимает или долго нажимает ссылку на URL. Реализация этого метода является необязательной. По умолчанию текстовое представление открывает приложение, ответственное за обработку URL-типа и передает ему URL-адрес. Вы можете использовать этот метод для запуска альтернативного действия, например отображения веб-контента по URL-адресу в веб-представлении в текущем приложении.

Важно:

Связи в текстовых представлениях интерактивны, только если текстовое представление выбираемый, но неизменяемый. То есть, если значение UITextView выбираемым свойством является YES, а свойство isEditable - NO.

Ответ 3

Для Swift 3

textView.delegate = self

extension MyTextView: UITextViewDelegate 

    func textView(_ textView: UITextView, shouldInteractWith URL: URL, in characterRange: NSRange) -> Bool {

        GCITracking.sharedInstance.track(externalLink: URL)
        return true
    }
}

или если цель равнa >= IOS 10

func textView(_ textView: UITextView, shouldInteractWith URL: URL, in characterRange: NSRange, interaction: UITextItemInteraction) -> Bool

Ответ 4

Быстрая версия:

Ваша стандартная настройка UITextView должна выглядеть примерно так: не забудьте делегат и dataDetectorTypes.

var textView = UITextView(x: 10, y: 10, width: CardWidth - 20, height: placeholderHeight) //This is my custom initializer
textView.text = "dsfadsaf www.google.com"
textView.selectable = true
textView.dataDetectorTypes = UIDataDetectorTypes.Link
textView.delegate = self
addSubview(textView)

После окончания вашего класса добавьте эту часть:

class myVC: UIViewController {
    //viewdidload and other stuff here
}

extension MainCard: UITextViewDelegate {
    func textView(textView: UITextView, shouldInteractWithURL URL: NSURL, inRange characterRange: NSRange) -> Bool {
        //Do your stuff over here
        var webViewController = SVModalWebViewController(URL: URL)
        view.presentViewController(webViewController, animated: true, completion: nil)
        return false
    }
}

Ответ 5

В Swift 5 и iOS 12 вы можете использовать один из трех следующих шаблонов для взаимодействия со ссылками в UITextView.


# 1. Использование UITextView dataDetectorTypes.

Самый простой способ взаимодействия с телефонными номерами, URL-адресами или адресами в UITextView - это использование свойства dataDetectorTypes. Пример кода ниже показывает, как его реализовать. С этим кодом, когда пользователь нажимает на телефонный номер, появляется UIAlertController.

import UIKit

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()

        let textView = UITextView()
        textView.text = "Phone number: +33687654321"
        textView.isUserInteractionEnabled = true
        textView.isEditable = false
        textView.isSelectable = true
        textView.dataDetectorTypes = [.phoneNumber]
        textView.isScrollEnabled = false

        textView.translatesAutoresizingMaskIntoConstraints = false
        view.addSubview(textView)
        textView.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
        textView.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true
        textView.leadingAnchor.constraint(equalTo: view.layoutMarginsGuide.leadingAnchor).isActive = true
    }

}

# 2. Использование UITextViewDelegate textView(_:shouldInteractWith:in:interaction:) метод

Если вы хотите выполнить какое-то настраиваемое действие вместо того, чтобы всплывающий UIAlertController при нажатии на телефонный номер при использовании dataDetectorTypes, вам нужно настроить UIViewController соответствие протоколу UITextViewDelegate и реализовать textView(_:shouldInteractWith:in:interaction:). Код ниже показывает, как это реализовать:

import UIKit

class ViewController: UIViewController, UITextViewDelegate {

    override func viewDidLoad() {
        super.viewDidLoad()

        let textView = UITextView()
        textView.delegate = self
        textView.text = "Phone number: +33687654321"
        textView.isUserInteractionEnabled = true
        textView.isEditable = false
        textView.isSelectable = true
        textView.dataDetectorTypes = [.phoneNumber]
        textView.isScrollEnabled = false

        textView.translatesAutoresizingMaskIntoConstraints = false
        view.addSubview(textView)
        textView.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
        textView.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true
        textView.leadingAnchor.constraint(equalTo: view.layoutMarginsGuide.leadingAnchor).isActive = true
    }

    func textView(_ textView: UITextView, shouldInteractWith URL: URL, in characterRange: NSRange, interaction: UITextItemInteraction) -> Bool {
        /* perform your own custom actions here */
        print(URL) // prints: "tel:+33687654321"

        return false // return true if you also want UIAlertController to pop up
    }

}

# 3. Использование NSAttributedString и NSAttributedString.Key.link

В качестве альтернативы вы можете использовать NSAttributedString и установить URL для его атрибута NSAttributedString.Key.link Пример кода ниже показывает возможную реализацию этого. С этим кодом, когда пользователь нажимает на атрибутивную строку, появляется UIAlertController.

import UIKit

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()

        let attributedString = NSMutableAttributedString(string: "Contact: ")
        let phoneUrl = NSURL(string: "tel:+33687654321")! // "telprompt://+33687654321" also works
        let attributes = [NSAttributedString.Key.link: phoneUrl]
        let phoneAttributedString = NSAttributedString(string: "phone number", attributes: attributes)
        attributedString.append(phoneAttributedString)

        let textView = UITextView()
        textView.attributedText = attributedString
        textView.isUserInteractionEnabled = true
        textView.isEditable = false
        textView.isSelectable = true
        textView.isScrollEnabled = false

        textView.translatesAutoresizingMaskIntoConstraints = false
        view.addSubview(textView)
        textView.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
        textView.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true
        textView.leadingAnchor.constraint(equalTo: view.layoutMarginsGuide.leadingAnchor).isActive = true
    }

}

Ответ 6

У меня есть динамический контент в текстовом виде, который может содержать ссылку. Функция shouldInteractWithURL вызывается только тогда, когда пользователь долго нажимает на ссылку, но не нажимает на ссылку. Пожалуйста, переадресуйте, если какой-либо приятель имеет ссылку на него.

Ниже приведен фрагмент кода.

UITextView *ltextView = [[UITextView alloc] init];
[ltextView setScrollEnabled:YES];
[ltextView setDataDetectorTypes:UIDataDetectorTypeLink];
ltextView.selectable = YES;
[ltextView setEditable:NO];
ltextView.userInteractionEnabled = YES;
ltextView.delegate = (id)self;
ltextView.delaysContentTouches = NO;
[self.view addsubview:ltextview];

- (BOOL)textView:(UITextView *)textView shouldInteractWithURL:(NSURL *)URL inRange:(NSRange)characterRange{

    [self.mActionDelegate userClickedOnImageLinkFromWebview:URL];

    NSLog(@"urls is :- %@",URL);
    return FALSE;
}

Вышеуказанный метод делегата не вызывается при нажатии.

С уважением, Рохит Янкар

Ответ 7

Я не пробовал это сам, но вы можете попробовать реализовать метод application:handleOpenURL: в делетете приложения - похоже, что все запросы openURL проходят через этот обратный вызов.

Ответ 8

Не знаете, как бы вы перехватили обнаруженную ссылку на данные или какую функцию вам нужно выполнить. Но вы можете использовать метод didFeginEditing TextField для запуска теста/сканирования через текстовое поле, если вы знаете, что вы ищете... как сравнение текстовых строк, которые соответствуют формату ### - ### - ####, или начать с "www." чтобы захватить эти поля, но вам нужно будет написать небольшой код, чтобы обнюхать строку текстовых полей, скорректировать то, что вам нужно, а затем извлечь ее для использования вашей функции. Я не думаю, что это было бы так сложно, как только вы сузили именно то, что вы хотели, а затем сосредоточили внимание на том, что ваш оператор if() фильтрует до очень специфического соответствия шаблону того, что вам нужно.

Из-за этого подразумевается, что пользователь коснется текстового поля, чтобы активировать функцию didBeginEditing(). Если это не тот тип взаимодействия с пользователем, который вы искали, вы могли бы просто использовать триггерный таймер, который начинается с ViewDidAppear() или другого на основе потребности и проходит через строку текстовых полей, а затем в конце вы пробегаете строку текстового поля методы, которые вы создали, вы просто отключите Таймер.

Ответ 9

application:handleOpenURL: вызывается, когда другое приложение открывает ваше приложение, открывая URL-адрес с помощью схемы, поддерживаемой вашим приложением. Он не вызывается, когда ваше приложение начинает открывать URL-адрес.

Я думаю, что единственный способ сделать то, что хочет Владимир, - это использовать UIWebView вместо UITextView. Сделайте свой контроллер представления UIWebViewDelegate, установите делегат UIWebView в контроллер представления и в контроллере представления выполните webView:shouldStartLoadWithRequest:navigationType:, чтобы открыть [request URL] в представлении вместо того, чтобы выйти из приложения и открыть его в Mobile Safari.

Ответ 10

Swift 4:

1) Создайте следующий класс (подклассифицированный UITextView):

import Foundation

protocol QuickDetectLinkTextViewDelegate: class {
    func tappedLink()
}

class QuickDetectLinkTextView: UITextView {

    var linkDetectDelegate: QuickDetectLinkTextViewDelegate?

    override init(frame: CGRect, textContainer: NSTextContainer?) {
        super.init(frame: frame, textContainer: textContainer)

    }

    required init?(coder aDecoder: NSCoder) {
         super.init(coder: aDecoder)
    }

    override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
        let glyphIndex: Int? = layoutManager.glyphIndex(for: point, in: textContainer, fractionOfDistanceThroughGlyph: nil)
        let index: Int? = layoutManager.characterIndexForGlyph(at: glyphIndex ?? 0)
        if let characterIndex = index {
            if characterIndex < textStorage.length {
                if textStorage.attribute(NSLinkAttributeName, at: characterIndex, effectiveRange: nil) != nil {
                    linkDetectDelegate?.tappedLink()
                    return self
                }
            }
        }

        return nil
    }
}


2) Где бы вы ни настраивали свой текст, сделайте следующее:

//init, viewDidLoad, etc
textView.linkDetectDelegate = self

//outlet
@IBOutlet weak var textView: QuickDetectLinkTextView!

//change ClassName to your class
extension ClassName: QuickDetectLinkTextViewDelegate {
    func tappedLink() {
        print("Tapped link, do something")
    }
}


Если вы используете раскадровку, убедитесь, что ваше текстовое изображение выглядит так в инспекторе правой панели:
введите описание изображения здесь



Вуаля! Теперь вы сразу же получаете ссылку, а не URL-адрес должен использовать метод URL-адреса