检测UITableViewCell中的UITextView中的数据

我在UITableViewCell子类中有一个UITextView 。 它具有editableuserInteractionEnabled都设置为NO 。 这允许UITextView检测数据,如链接和电话号码。 数据正确检测,但由于userInteraction被禁用,它不能响应该数据上的水龙头。 如果我将userInteractionEnabled设置为YES ,它可以正常工作,但是UITableViewCell不能被选中,因为UITextView会触摸它。

我想跟随链接,如果用户点击它,但我想didSelectRowAtIndexPath:被调用,如果水龙头在基本文字。

我认为正确的做法是UITextView ,并将触摸传递给单元格,但我似乎无法find一种方法来检测是否在一个链接的水龙头。

这是一个类似的问题,但答案只是通过所有的触及细胞。 我只想通过触摸,如果他们不在一个检测到的数据。 在UITableViewCell中的UITextView上启用启用dataDetectorTypes

1.使用hitTest(_:with:)

UIView有一个名为hitTest(_:with:) ,其定义如下:

 func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? 

返回包含指定点的视图层次结构(包括它本身)中接收器的最远后代。

UITextViewUIView的子类,你可以在你想创build的UITextView任何子类中实现这个方法。


下面的Swift 3示例显示了一个包含单个静态UITableViewCellUITableViewCellembedded一​​个UITextView 。 在UITextView内部的任何一个链接点击将启动Safari应用程序; 任何在UITextView内的基本文本的点击都会触发一个push到下面的UIViewController

LinkTextView.swift

 import UIKit class LinkTextView: UITextView { override init(frame: CGRect, textContainer: NSTextContainer?) { super.init(frame: frame, textContainer: textContainer) configure() } required init?(coder aDecoder: NSCoder) { super.init(coder: aDecoder) configure() } func configure() { isScrollEnabled = false isEditable = false isUserInteractionEnabled = true isSelectable = true dataDetectorTypes = .link } override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? { // Get the character index from the tap location let characterIndex = layoutManager.characterIndex(for: point, in: textContainer, fractionOfDistanceBetweenInsertionPoints: nil) // if we detect a link, handle the tap by returning self... if let _ = textStorage.attribute(NSLinkAttributeName, at: characterIndex, effectiveRange: nil) { return self } // ... otherwise return nil ; the tap will go on to the next receiver return nil } } 

TextViewCell.swift

 import UIKit class TextViewCell: UITableViewCell { @IBOutlet weak var textView: LinkTextView! } 

TableViewController.swift

 import UIKit class TableViewController: UITableViewController { @IBOutlet weak var cell: TextViewCell! override func viewDidLoad() { super.viewDidLoad() // Add text to cell's textView let text = "http://www.google.com Lorem ipsum dolor sit amet, consectetur adipiscing elit, http://www.yahoo.com sed do eiusmod tempor incididunt ut labore et dolore magna aliqua." cell.textView.text = text } } 

在这里输入图像说明


2.使用point(inside:with:)

作为重写hitTest(_:with:)的替代方法,可以使用point(inside:with:)point(inside:with:)有以下声明:

 func point(inside point: CGPoint, with event: UIEvent?) -> Bool 

返回一个布尔值,指示接收者是否包含指定的点。


下面的代码演示了如何在你的UITextView子类中实现point(inside:with:)而不是hitTest(_:with:)

LinkTextView.swift

 import UIKit class LinkTextView: UITextView { override init(frame: CGRect, textContainer: NSTextContainer?) { super.init(frame: frame, textContainer: textContainer) configure() } required init?(coder aDecoder: NSCoder) { super.init(coder: aDecoder) configure() } func configure() { isScrollEnabled = false isEditable = false isUserInteractionEnabled = true isSelectable = true dataDetectorTypes = .link } override func point(inside point: CGPoint, with event: UIEvent?) -> Bool { // Get the character index from the tap location let characterIndex = layoutManager.characterIndex(for: point, in: textContainer, fractionOfDistanceBetweenInsertionPoints: nil) // if we detect a link, handle the tap by returning true... if let _ = textStorage.attribute(NSLinkAttributeName, at: characterIndex, effectiveRange: nil) { return true } // ... otherwise return false ; the tap will go on to the next receiver return false } } 

完整的项目在这个GitHub 仓库中可用: LinkTextViewCell 。

您可以通过阅读Swifty方法来处理单元格中的链接使用UITextView来了解更多关于在UITableViewCellpipe理UITextView

通过阅读苹果指南和示例代码:“事件传递:响应者链”,您可以了解更多关于hitTest(_:with:)point(inside:with:)之间区别的信息。

我遇到过同样的问题。 我通过inheritanceUITextView并添加一个协议来解决它:

 @protocol SOTextViewDelegate; @interface SOTextView : UITextView @property (nonatomic, weak) id<SOTextViewDelegate> soDelegate; @end @protocol SOTextViewDelegate <NSObject> @optional - (void)soTextViewWasTapped:(SOTextView *)soTextview; @end 

在实施中,我刚刚添加了这个:

 - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event { if (self.selectedRange.length == 0 && [_soDelegate respondsToSelector:@selector(soTextViewWasTapped:)])) [_soDelegate soTextViewWasTapped:self]; } 

这个委托会告诉自定义的单元格textView被点击。 我的自定义单元格也有一个委托,以触发其实际select。

现在你可以点击一个链接,它会打开,你可以点击textView并得到通知,你仍然可以select文本,点击取消select它。