Как обнаружить все ссылки в тексте и обработать нажатием на них [дублировать]

Другим случаем, когда NullReferenceExceptions может случиться, является (неправильное) использование оператора as :

class Book {
    public string Name { get; set; }
}
class Car { }

Car mycar = new Car();
Book mybook = mycar as Book;   // Incompatible conversion --> mybook = null

Console.WriteLine(mybook.Name);   // NullReferenceException

Здесь Book и Car являются несовместимыми типами; a Car не может быть преобразован / передан в Book. Когда этот сбой завершается неудачно, as возвращает null. Используя mybook после этого, вы вызываете NullReferenceException.

В общем случае вы должны использовать cast или as, как показано ниже:

Если вы ожидаете преобразования типа в всегда преуспевает (т. е. вы знаете, какой объект должен быть впереди времени), тогда вы должны использовать cast:

ComicBook cb = (ComicBook)specificBook;

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

ComicBook cb = specificBook as ComicBook;
if (cb != null) {
   // ...
}

86
задан Vladimir 31 March 2010 в 09:51
поделиться

10 ответов

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

- (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 и перезапись -(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: в вашем делегате.

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

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

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

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

Это сделало трюк для меня.

125
ответ дан Aleksander Azizi 1 September 2018 в 08:02
поделиться
  • 1
    Наконец-то реальный ответ! Простая и крутая идея. Спасибо, это работает. Это было давно, так что я обошелся без него уже. Все еще может помочь в будущем. Небольшая коррекция, однако, результат от супер в ветке else должен быть возвращен: return [super openURL: url]; – Vladimir 6 December 2010 в 10:13
  • 2
    Круто! Я сделал предложенную коррекцию. Ура! – fsaint 6 December 2010 в 12:46
  • 3
    Вы также можете классифицировать UIApplication и заменить реализацию openURL. Хотя таким образом сложно (но не невозможно) ссылаться на первоначальную реализацию. – mxcl 6 December 2010 в 14:01
  • 4
    FYI - я опубликовал браузер Gibbub BrowserViewController, который полностью реализует это, а также поддерживает ссылки, которые вызывается из UIWebView здесь: github.com/nbuggia/Browser-View-Controller--iPhone - . – Nathan Buggia 5 November 2011 в 04:53
  • 5
    Кажется, это работает только для веб-ссылок, а не для автоформатированных телефонных номеров. – azdev 6 March 2012 в 00:17

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

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

0
ответ дан A. Jesse Jiryu Davis 1 September 2018 в 08:02
поделиться

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

Ваша стандартная настройка 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
    }
}
3
ответ дан Esqarrouth 1 September 2018 в 08:02
поделиться

С Swift 3 и i0S 10 самый простой способ взаимодействия с номерами телефонов, URL-адресами или адресами в UITextView - использовать UIDataDetectorTypes . В приведенном ниже коде показано, как отображать номер телефона в UITextView, чтобы пользователь мог взаимодействовать с ним.

import UIKit

class ViewController: UIViewController {

    // Link this outlet to a UITextView in your Storyboard
    @IBOutlet weak var textView: UITextView!

    override func viewDidLoad() {
        super.viewDidLoad()

        textView.text = "+33687654321"
        textView.isUserInteractionEnabled = true // default: true
        textView.isEditable = false // default: true
        textView.isSelectable = true // default: true
        textView.dataDetectorTypes = [.phoneNumber]
    }

}

С помощью этого кода при нажатии на номер телефона UIAlertController будет pop.


В качестве альтернативы вы можете использовать NSAttributedString :

import UIKit

class ViewController: UIViewController {

    // Link this outlet to a UITextView in your Storyboard
    @IBOutlet weak var textView: UITextView!

    override func viewDidLoad() {
        super.viewDidLoad()

        let phoneUrl = NSURL(string: "tel:+33687654321")! // "telprompt://+33687654321" also works
        let attributes = [NSLinkAttributeName: phoneUrl]
        let attributedString = NSAttributedString(string: "phone number", attributes: attributes)

        textView.attributedText = attributedString
        textView.isUserInteractionEnabled = true // default: true
        textView.isEditable = false // default: true
        textView.isSelectable = true // default: true
    }

}

С помощью этого кода при нажатии на атрибут строка, появится UIAlertController.


Однако вы можете выполнить некоторые пользовательские действия вместо того, чтобы всплывать UIAlertController, когда вы нажимаете на номер телефона. Или вы можете захотеть, чтобы UIAlertController всплывал и выполнял ваше собственное действие в одно и то же время.

В обоих случаях вам нужно будет сделать ваш UIViewController совместимым с UITextViewDelegate протоколом и реализовать textView(_:shouldInteractWith:in:interaction:) . Код ниже показывает, как это сделать.

import UIKit

class ViewController: UIViewController, UITextViewDelegate {

    // Link this outlet to a UITextView in your Storyboard
    @IBOutlet weak var textView: UITextView!

    override func viewDidLoad() {
        super.viewDidLoad()

        textView.delegate = self

        textView.text = "+33687654321"
        textView.isUserInteractionEnabled = true
        textView.isEditable = false
        textView.isSelectable = true
        textView.dataDetectorTypes = [.phoneNumber]
    }

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

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

}

С помощью этого кода при нажатии на номер телефона не появится UIAlertController, и вместо этого вы получите следующую распечатку в консоли:

tel: +33687654321

2
ответ дан Imanou Petit 1 September 2018 в 08:02
поделиться

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")
    }
}

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

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

1
ответ дан Josh O'Connor 1 September 2018 в 08:02
поделиться
  • 1
    также: если вы хотите, чтобы URL-адрес не обрабатывался, просто установите метод shouldInteractWith для возврата false – Josh O'Connor 29 November 2017 в 20:24
  • 2
    Думайте, что у вас есть куча проблем, например, что происходит, когда вы не нажимаете ссылку. Т.е. я не думаю, что текстовое представление будет работать нормально больше, поскольку нуль возвращается. Выбор также изменится при нажатии ссылки, потому что в этом случае возвращается self. – Drew McCormack 7 March 2018 в 11:08
  • 3
    отлично работает для меня, вам нужно обрабатывать такие случаи для ваших нужд – Josh O'Connor 7 March 2018 в 19:39
  • 4
    слабый var linkDetectDelegate: QuickDetectLinkTextViewDelegate? – maslovsa 3 July 2018 в 06:06

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

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

0
ответ дан Newbyman 1 September 2018 в 08:02
поделиться

У меня динамический контент в текстовом представлении, который может содержать ссылку. Функция 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;
}

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

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

1
ответ дан Phan Van Linh 1 September 2018 в 08:02
поделиться

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

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

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

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

Важно:

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

47
ответ дан Rajan Balana 1 September 2018 в 08:02
поделиться
  • 1
    Я рад, что они добавили это в UITextViewDelegate. – fsaint 27 January 2014 в 17:46
  • 2
    К сожалению, вы все равно закончите использование UIWebView, если хотите сделать ссылку на другой текст , а не сам URL. Тег <a> по-прежнему остается лучшим способом в этом случае. – Matt Quiros 27 February 2014 в 09:56
  • 3
    Это должен быть принятый ответ. – andybons 1 July 2014 в 03:44

Для 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
    }
}

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

func textView(_ textView: UITextView, shouldInteractWith URL: URL, in characterRange: NSRange, interaction: UITextItemInteraction) -> Bool
3
ответ дан Ryan Heitner 1 September 2018 в 08:02
поделиться

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

0
ответ дан Vladimir 1 September 2018 в 08:02
поделиться
Другие вопросы по тегам:

Похожие вопросы: