检测UITableViewCell中的UITextView中的数据
我在UITableViewCell
子类中有一个UITextView
。 它具有editable
和userInteractionEnabled
都设置为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?
返回包含指定点的视图层次结构(包括它本身)中接收器的最远后代。
UITextView
是UIView
的子类,你可以在你想创build的UITextView
任何子类中实现这个方法。
下面的Swift 3示例显示了一个包含单个静态UITableViewCell
。 UITableViewCell
embedded一个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
来了解更多关于在UITableViewCell
pipe理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它。