如何拦截点击UITextView中的链接?

时间:2010-03-30 09:04:42

标签: iphone objective-c uitextview datadetectortypes

当用户触摸UITextView中的自动检测电话链接时,是否可以执行自定义操作。请不要建议使用UIWebView。

请不要只重复苹果课程中的文字参考   - 当然我已经读过了。

感谢。

9 个答案:

答案 0 :(得分:134)

更新:来自

- (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);

这对我有用。

答案 1 :(得分:50)

在iOS 7或更高版本中

您可以使用以下UITextView委托方法:

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

如果用户点击或长按URL链接,则文本视图会调用此方法。此方法的实现是可选的。默认情况下,文本视图会打开负责处理URL类型的应用程序并将URL传递给它。您可以使用此方法触发替代操作,例如在当前应用程序的Web视图中的URL处显示Web内容。

重要提示:

  

文本视图中的链接仅在文本视图中是交互式的   可选但不可编辑。也就是说,如果是UITextView的值   可选属性为YES,isEditable属性为NO。

答案 2 :(得分:6)

对于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 :(得分:5)

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

答案 4 :(得分:2)

使用Swift 3和i0S 10,与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

作为替代方案,您可以使用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,您将在控制台中获得以下打印:

  

电话:33687654321

答案 5 :(得分:0)

我自己没有尝试过,但您可以尝试在应用程序委托中实现application:handleOpenURL:方法 - 看起来所有openURL请求都会通过此回调。

答案 6 :(得分:0)

不确定如何拦截检测到的数据链接,或者需要运行哪种类型的功能。但是,如果您知道要查找的内容,则可以使用didBeginEditing TextField方法在文本字段中运行测试/扫描。例如,比较符合### - ### - #### format的文本字符串,或者以“www。”开头。抓住那些字段,但你需要编写一些代码来嗅探文本域字符串,重新调整你需要的东西,然后提取它以供你的函数使用。一旦你缩小了你想要的内容,然后把你的if()语句过滤到你所需要的非常具体的匹配模式,我认为这不会那么困难。

这意味着用户将触摸文本框以激活didBeginEditing()。如果这不是您正在寻找的用户交互类型,您可以使用触发器Timer,它根据需要在ViewDidAppear()或其他基础上启动并运行textfields字符串,然后在您运行textfield字符串的末尾您构建的方法,您只需关闭Timer。

答案 7 :(得分:0)

当另一个应用打开您的应用时,会通过打开您的应用支持的方案的网址来调用

application:handleOpenURL:。当您的应用开始打开网址时,系统不会调用它。

我认为做Vladimir想要的唯一方法是使用UIWebView而不是UITextView。使视图控制器实现UIWebViewDelegate,将UIWebView的委托设置为视图控制器,并在视图控制器中实现webView:shouldStartLoadWithRequest:navigationType:以在视图中打开[request URL],而不是退出应用程序并在Mobile Safari中打开它。 / p>

答案 8 :(得分:0)

斯威夫特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")
    }
}


如果您正在使用故事板,请确保右侧窗格标识检查器中的文本视图如下所示:
enter image description here



瞧!现在,您可以立即获取链接,而不是URL shouldInteractWith URL方法