检测UITextView上的轻击只能检测到取消操作。

15

我一直在努力使用Swift检测UITextView上的轻击。

我的UITextView在一个表格中,我必须能够检测链接并按下它们,这些链接的长度是未知的。

此外,如果我点击了单元格而不是链接,我希望将一个新的UIViewController推入我的导航控制器堆栈。

我尝试创建自己的文本视图以覆盖touchesCancelled,但没有成功。它会检测到取消操作,但在真实设备上却不被认为是轻击。

这个bug在模拟器中不会出现,但似乎我无法在真实设备上轻击,只有长按才有效。

class LinkTextView: UITextView {
    override func touchesCancelled(touches: Set<NSObject>!, withEvent event: UIEvent!) {
         self.textViewWasTapped(self) 
    }
}

我尝试直接添加手势识别器,但没有成功。它根本没有调用手势识别器。

我将UIGestureReconizer委托添加到我的UIViewController中,并在我的代码中添加了这些行:

func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
     var singleTap : UIGestureRecognizer = UIGestureRecognizer(target: self, action: "tapTextView:")
        singleTap.delegate = self
             cell.mTextOutlet.attributedText = myMutableString
             cell.mTextOutlet.addGestureRecognizer(singleTap) 

在我的LinkTextView类中:

class LinkTextView: UITextView {
    func tapTextView(stapGesture: UIGestureRecognizer){
        println("TAPPING1")
    }
}

我在论坛上查看了这篇帖子:post。它建议使用CCHLinkTextView。我尝试使用它,但我想要的是自动检测链接,而普通的UITextView确实可以做到。

我尝试使用接口构建器中的复选框来解析CHHLinkTextView中的链接,但它不起作用。我在文档中没有看到任何建议可以完成此操作的内容。

我该如何继续进行?

2个回答

11

你在对UITextView进行子类化的第一次尝试非常接近,但是你需要覆盖所有的touches*方法,而不仅仅是touchesCancelled

  • touchesBegan
  • touchesMoved
  • touchesEnded
  • touchesCancelled

在覆盖的方法中,通过获取textView的nextResponder()将触摸事件传递给响应者链,检查它是否为nil,并在下一个响应者上调用该方法。

这个方案的原理是因为如果触摸事件触发了URL,UITextView将拦截它,而UIResponder方法将不会被调用。通过在tableViewCell或其他地方实现textView:shouldInteractWithURL:inRange,你可以自己尝试并看到它在任何触摸事件之前就被调用了。

这应该是你尝试做的最小要求(虽然有点重复但很简短):

class PassThroughTextView: UITextView {

    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        if let next = next {
            next.touchesBegan(touches, with: event)
        } else {
            super.touchesBegan(touches, with: event)
        }
    }

    override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
        if let next = next {
            next.touchesEnded(touches, with: event)
        } else {
            super.touchesEnded(touches, with: event)
        }
    }

    override func touchesCancelled(_ touches: Set<UITouch>, with event: UIEvent?) {
        if let next = next {
            next.touchesCancelled(touches, with: event)
        } else {
            super.touchesCancelled(touches, with: event)
        }
    }

    override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
        if let next = next {
            next.touchesMoved(touches, with: event)
        } else {
            super.touchesMoved(touches, with: event)
        }
    }
}

// In case you want to do anything with the URL or textView in your tableViewCell...
class TableViewCell: UITableViewCell, UITextViewDelegate {
    @IBOutlet var textView: PassThroughTextView!

    func textView(textView: UITextView, shouldInteractWithURL URL: NSURL, inRange characterRange: NSRange) -> Bool {
        println("textView shouldInteractWithURL")
        return true
    }

}

next 来自哪里? - Andrew Kirna
我猜它被继承为某种超类(也许是NSObject或UIView)。感谢简单的答案。这对我有用:] 我的UICollectionViewCell现在带有嵌套的UITextView,可以传递点击给拥有它们的单元格来执行翻转动画! - Andrew Kirna
1
抱歉耽搁了,但为了后人的利益,nextUIResponder的成员:https://developer.apple.com/documentation/uikit/uiresponder - Ralfonso

8

我按照Ralfonso的说法尝试了,但没有成功,但它帮助我意识到我有一个手势识别器冲突。结果我不必覆盖UITextView的所有4个方法,只需覆盖touchesBegan方法。 在viewDidLoad中我所做的是添加一个手势识别器来关闭键盘:

      var tapOutTextField: UITapGestureRecognizer = UITapGestureRecognizer(target: self, action: "dismissKeyboard")
      self.view.addGestureRecognizer(tapOutTextField)

让我感到困惑,走了一条错误的路是因为touchesBegan实际上是在延迟之后调用的(touchCancelled也是如此),我无法得到与UIButton相同的行为。所有这些都是由于手势识别器冲突造成的。


1
很高兴你能解决它!手势识别器可能会在其他底层操作中显得有些奇怪 - 在研究你的问题之前,我并不知道预先链接交互。但需要记住的一件事是,如果你在touchesBegan:中没有调用super,文档说你还必须重写其他触摸处理方法:https://developer.apple.com/library/ios/documentation/UIKit/Reference/UIResponder_Class/index.html#//apple_ref/occ/instm/UIResponder/touchesBegan:withEvent: 这样做可以避免以后出现奇怪的行为。 - Ralfonso

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接