web-dev-qa-db-ja.com

UITextViewでリンクのクリックをインターセプトする方法は?

ユーザーがUITextViewで自動検出された電話リンクをタッチしたときにカスタムアクションを実行することは可能ですか?代わりにUIWebViewを使用することはお勧めしません。

そして、Appleクラス参照からのテキストを繰り返すだけではありません-すでに読んでいます。

ありがとう。

96
Vladimir

更新: ios1 から、

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

ios7 以降およびUITextViewにはデリゲートメソッドがあります。

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

リンクへのクリックをインターセプトします。そして、これはそれを行う最良の方法です。

ios6 以前の場合、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);
_

3番目のパラメーターは、アプリケーションのクラス名です。したがって、この行を次のように置き換えます。

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

これは私のためにトリックをしました。

139
fsaint

IOS 7以降

次のUITextViewデリゲートメソッドを使用できます。

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

ユーザーがURLリンクをタップまたは長押しすると、テキストビューがこのメソッドを呼び出します。このメソッドの実装はオプションです。デフォルトでは、テキストビューはURLタイプを処理するアプリケーションを開き、URLを渡します。このメソッドを使用して、現在のアプリケーション内のWebビューのURLでWebコンテンツを表示するなど、代替アクションをトリガーできます。

重要:

テキストビューのリンクは、テキストビューが選択可能であるが編集できない場合にのみインタラクティブです。つまり、UITextViewの値が選択可能なプロパティの場合はYESで、isEditableプロパティはNOです。

50
Rajan Balana

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
6
Ryan Heitner

Swiftバージョン:

標準の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
Esqarrouth

Swift 5およびiOS 12では、UITextView内のリンクと対話するために、次の3つのパターンのいずれかを使用できます。


#1。 UITextViewdataDetectorTypes プロパティを使用します。

UITextViewで電話番号、URL、またはアドレスを操作する最も簡単な方法は、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。 UITextViewDelegatetextView(_:shouldInteractWith:in:interaction:) メソッドを使用する

UIAlertControllerを使用中に電話番号をタップしたときにdataDetectorTypesをポップアップする代わりにカスタムアクションを実行する場合は、UIViewControllerUITextViewDelegateプロトコルに準拠させ、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を使用して、その_NSAttributedString.Key.link_属性にURLを設定できます。以下のサンプルコードは、その実装例を示しています。このコードでは、ユーザーが属性付き文字列をタップすると、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
    }

}
_
2
Imanou Petit

テキストビューに動的コンテンツがあり、リンクが含まれている場合があります。 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
Rohit

application:handleOpenURL:は、別のアプリが開くときに呼び出されますyourアプリがサポートするスキームでURLを開くことによって。アプリがURLを開くときに呼び出されることはありません。

Vladimirが望んでいることを行う唯一の方法は、UITextViewではなくUIWebViewを使用することだと思います。 View ControllerでUIWebViewDelegateを実装し、UIWebViewのデリゲートをView Controllerに設定し、View Controllerでアプリを終了してMobile Safariで開くのではなく、ビューでwebView:shouldStartLoadWithRequest:navigationType:を開くために[request URL]を実装します。

私はそれを試していませんが、application:handleOpenURL:アプリケーションデリゲートのメソッド-すべてのopenURLリクエストがこのコールバックを通過するように見えます。

0
Vladimir

検出されたデータリンクをどのようにインターセプトするか、または実行する必要がある機能のタイプがわからない。しかし、探しているものがわかっている場合は、didBeginEditing TextFieldメソッドを使用して、テスト/スキャンをテキストフィールドで実行できる場合があります。たとえば、###-###-####形式に一致するテキスト文字列を比較したり、または「www」で始まりますこれらのフィールドを取得するには、テキストフィールドの文字列をスニッフィングするための小さなコードを作成し、必要なものを調整してから、関数の使用のために抽出する必要があります。必要なものを正確に絞り込み、if()ステートメントフィルターを必要なものの非常に具体的な一致パターンに絞り込んだら、これはそれほど難しいとは思いません。

当然のことですが、これはユーザーがdidBeginEditing()をアクティブにするためにテキストボックスをタッチすることを意味します。それがあなたが探していたユーザーインタラクションのタイプではない場合、ViewDidAppear()または必要に応じて開始し、テキストフィールド文字列を実行し、最後にテキストフィールド文字列を実行するトリガータイマーを使用できます構築したメソッドは、タイマーをオフに戻すだけです。

0
Newbyman

スウィフト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")
    }
}


ストーリーボードを使用している場合は、右ペインのIDインスペクターでテキストビューが次のようになっていることを確認してください。
enter image description here



ボイラ!これで、URL shouldInteractWith URLメソッドの代わりに、すぐにリンクタップを取得できます

0
Josh O'Connor