108

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

请不要只是重复苹果类参考中的文本——当然我已经读过了。

谢谢。

4

9 回答 9

153

更新:从

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

这对我有用。

于 2010-12-02T17:39:27.850 回答
52

在 iOS 7 或更高版本中

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

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

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

重要的:

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

于 2013-11-11T08:42:00.737 回答
10

对于斯威夫特 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
于 2017-01-03T07:35:58.887 回答
9

在 Swift 5 和 iOS 12 中,您可以使用以下三种模式之一来与UITextView.


#1。使用UITextViewdataDetectorTypes属性。

与 a 中的电话号码、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'stextView(_: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。使用NSAttributedStringNSAttributedString.Key.link

作为替代方案,您可以使用并为其属性NSAttributedString设置 a 。下面的示例代码显示了它的可能实现。使用此代码,当用户点击属性字符串时,会弹出一个。URLNSAttributedString.Key.linkUIAlertController

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
    }

}
于 2016-06-30T12:33:51.490 回答
7

斯威夫特版本:

您的标准 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
    }
}
于 2015-06-24T20:33:21.267 回答
3

斯威夫特 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 shouldInteractWith URL 方法时

于 2017-11-29T18:59:09.640 回答
1

application:handleOpenURL:当另一个应用程序通过使用您的应用程序支持的方案打开 URL 来打开您的应用程序时调用。当您的应用开始打开 ​​URL 时不会调用它。

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

于 2010-06-08T02:31:18.640 回答
0

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

于 2010-03-31T08:57:59.270 回答
0

不确定如何拦截检测到的数据链接,或者需要运行什么类型的函数。但是,如果您知道要查找的内容,则可以使用 didBeginEditing TextField 方法对文本字段进行测试/扫描。例如比较符合###-###-#### 格式的文本字符串,或以“www”开头。获取这些字段,但是您需要编写一些代码来嗅探文本字段字符串,重新整理您需要的内容,然后将其提取以供您的函数使用。我认为这不会那么困难,一旦你准确地缩小了你想要的范围,然后将你的 if() 语句过滤器集中到你需要的非常具体的匹配模式上。

当然,这意味着用户将触摸文本框以激活 didBeginEditing()。如果这不是您正在寻找的用户交互类型,您可以只使用触发器计时器,它从 ViewDidAppear() 或其他根据需要开始并贯穿文本字段字符串,然后在结束时运行文本字段字符串您构建的方法,您只需关闭 Timer。

于 2010-04-04T23:47:34.703 回答