web-dev-qa-db-ja.com

UITextViewのタップを検出すると、キャンセルのみが検出されます

SwiftでUITextViewのタップを検出するのに苦労しています。

私のUITextViewsはテーブルにあり、リンクを検出して押すことができなければなりません。それらのリンクの長さは不明です。

また、リンクをタップせずにセルをタップした場合は、ナビゲーションコントローラースタックに新しいUIViewControllerをプッシュします。

TouchesCancelledを上書きするために独自のテキストビューを作成しようとしましたが、成功しませんでした。実際のデバイスのタップとは見なされないキャンセルを検出します。

シミュレーターではバグは発生しませんが、実際のデバイスをタップできないようです。長押しするだけで動作します。

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")
    }
}

私はフォーラムを見て、この投稿を見つけました: 投稿CHHLinkTextView を使用することをお勧めします。私はそれを使おうとしましたが、私が欲しいのはリンクを自動的に検出することです。これは通常のuitextviewが実際に行うことです。

インターフェイスビルダーでcheckBoxを使用してCHHLinkTextViewでリンクを解析しようとしましたが、機能しません。ドキュメントには、それが可能であることを示唆するものは何もありませんでした。

どうすればよいですか?

14
Swift Rabbit

Ralfonsoが言ったように成功しませんでしたが、ジェスチャー認識機能が競合していることに気づきました。 UITextViewの4つのメソッドすべてをオーバーライドする必要はなく、touchesBeganをオーバーライドするだけであることがわかりました。 viewDidLoadで行っていたのは、キーボードを閉じるためのジェスチャレコグナイザーを追加することでした。

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

意味がなく、間違った方向に私を送ったのは、touchesBeganが実際には遅延後に呼び出され(したがってtouchCancelled)、UIButtonと同じ動作を得ることができなかったということでした。このジェスチャレコグナイザーの競合が原因です。

7
Swift Rabbit

UITextViewのサブクラス化の最初の試みに非常に近いですが、touchesCancelledだけをオーバーライドするのではなく、すべての_touches*_メソッドをオーバーライドする必要があります。

  • touchesBegan
  • touchesMoved
  • touchesEnded
  • touchesCancelled

オーバーライドされたメソッドで、textViewのnextResponder()を取得してレスポンダーチェーンにタッチを送信し、それがnilでないことを確認して、次のレスポンダーでメソッドを呼び出します。

これが機能する理由は、UITextViewがURL上にある場合はタッチをインターセプトし、UIResponderメソッドが呼び出されることはないためです。_textView:shouldInteractWithURL:inRange_を実装して自分で試してください。 tableViewCellまたはどこでも、タッチイベントが渡される前に呼び出されることがわかります。

これは、あなたがやろうとしていることの最小値でなければなりません(繰り返しですが短いです):

_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
    }

}
_
9
Ralfonso