在UITableViewCell中检测UITextView中的数据 [英] Detect Data in UITextView in UITableViewCell

查看:359
本文介绍了在UITableViewCell中检测UITextView中的数据的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在 UITableViewCell 子类中有一个 UITextView 。它有可编辑 userInteractionEnabled 都设置为。这允许 UITextView 检测链接和电话号码等数据。正确检测数据,但由于禁用了userInteraction,因此无法响应该数据的点击。如果我将 userInteractionEnabled 设置为 YES ,它可以正常工作,但是 UITableViewCell



如果用户点击它,我想关注该链接,但我希望 didSelectRowAtIndexPath: to如果点击基本文本,则调用。



我认为正确的方法是子类 UITextView 并将触摸传递给单元格,但我似乎找不到检测点击是否在链接上的方法。



这是一个类似的问题,但答案只是将所有接触传递给细胞。我想只传递触摸,如果它们不在一块检测到的数据上。






2。使用 point(inside:with :)



作为覆盖 hitTest(_的替代方法) :with:),您可以使用 点(内:其中:) point(inside:with :) 具有以下声明:

  func point(内部点:CGPoint,事件:UIEvent?) - > Bool 




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







以下代码显示了如何实现点(内部) :在 UITextView 子类中使用:)而不是 hitTest(_:with :)



LinkTextView.swift

  import UIKit 

class LinkTextView:UITextView {

覆盖init(frame:CGRect,textContainer:NSTextContainer?){
super.init(frame:frame,textContainer: textContainer)
configure()
}

必需init?(编码器aDecoder:NSCoder){
super.init(编码器:aDecoder)
configure( )
}

func configure(){
isScrollEnabled = false
isEditable = false
isUserInteractionEnabled = true
isSelectable = true
dat aDetectorTypes = .link
}

覆盖func point(内部点:CGPoint,事件:UIEvent?) - > Bool {
//从抽头位置获取字符索引
let characterIndex = layoutManager.characterIndex(for:point,in:textContainer,fractionOfDistanceBetweenInsertionPoints:nil)

// if我们检测到一个链接,通过返回true来处理tap ...
if let _ = textStorage.attribute(NSLinkAttributeName,at:characterIndex,effectiveRange:nil){
return true
}

// ...否则返回false;点击将继续下一个接收者
返回false
}

}






这个GitHub仓库上有完整的项目: LinkTextViewCell



您可以在<$ c $内了解有关管理 UITextView 的更多信息c> UITableViewCell 阅读使用单元格中的链接处理UITextView的快速方法



您可以了解有关之间区别的更多信息hitTest(_:with :) 指向(内部:带:):通过阅读Apple的指南和示例代码:事件传递:响应者链


I have a UITextView inside a UITableViewCell subclass. It has editable and userInteractionEnabled both set to NO. This allows the UITextView to detect data such as links and phone numbers. The data is detected correctly, but because userInteraction is disabled, it cannot respond to taps on that data. If I set userInteractionEnabled to YES, it works fine, but then the UITableViewCell cannot be selected since the UITextView swallows the touch.

I want to follow the link if the user taps on it, but I want didSelectRowAtIndexPath: to be called if the tap is on basic text.

I think the right approach is to subclass UITextView and pass touches to the cell, but I can't seem to find a way to detect whether or not the tap was on a link.

This is a similar question, but the answer will just pass all touches to the cell. I want to only pass the touches if they are NOT on a piece of detected data. issue enabling dataDetectorTypes on a UITextView in a UITableViewCell

解决方案

1. Using hitTest(_:with:)

UIView has a method called hitTest(_:with:) that has the following definition:

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

Returns the farthest descendant of the receiver in the view hierarchy (including itself) that contains a specified point.

UITextView being a subclass of UIView, you can implement this method in any subclass of UITextView you may want to create.


The following Swift 3 example shows a UITableViewController that contains a single static UITableViewCell. The UITableViewCell embeds a UITextView. Any tap on a link inside the UITextView will launch Safari app; any tap on basic text inside the UITextView will trigger a push segue to the following 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. Using point(inside:with:)

As an alternative to override hitTest(_:with:), you can use point(inside:with:). point(inside:with:) has the following declaration:

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

Returns a Boolean value indicating whether the receiver contains the specified point.


The following code shows how to implement point(inside:with:) instead of hitTest(_:with:) in your UITextView subclass:

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
    }

}


The complete project is available on this GitHub repo: LinkTextViewCell.

You can learn more about managing a UITextView inside a UITableViewCell by reading Swifty Approach to Handling UITextViews With Links in Cells.

You can learn more about the difference between hitTest(_:with:) and point(inside:with:) by reading Apple's Guide and Sample Code: "Event Delivery: The Responder Chain".

这篇关于在UITableViewCell中检测UITextView中的数据的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆