在Swift中从UITextView获取单词

我知道Objective-C已经解决了这个问题,但是在Swift中我还没有看到任何解决scheme。 我试图从这个post转换解决scheme的代码,但我得到的错误:

func textTapped(recognizer: UITapGestureRecognizer){ var textView: UITextView = recognizer.view as UITextView var layoutManager: NSLayoutManager = textView.layoutManager var location: CGPoint = recognizer.locationInView(textView) location.x -= textView.textContainerInset.left location.y -= textView.textContainerInset.top var charIndex: Int charIndex = layoutManager.characterIndexForPoint(location, inTextContainer: textView.textContainer, fractionOfDistanceBetweenInsertionPoints: nil) if charIndex < textView.textStorage.length { // do the stuff println(charIndex) } } 

我认为这个问题是在这一行(请看这里的错误):

  var textView: UITextView = recognizer.view as UITextView 

…我基于这一行从Objective-C转换而来:

  UITextView *textView = (UITextView *)recognizer.view; 

最后,我也怀疑如何调用这个函数。 据我所知,函数应该传递给viewDidLoad()中的select器,如下所示:

  let aSelector: Selector = "textTapped:" let tapGesture = UITapGestureRecognizer(target: self, action: aSelector) tapGesture.numberOfTapsRequired = 1 view.addGestureRecognizer(tapGesture) 

因为我得到了前面提到的错误,我不确定它是否会起作用。 但我想我需要将textTapped函数(识别器)中的parameter passing给select器。 不过,我读过,你只能通过函数,而不是任何参数。

您需要将UITapGestureRecognizer添加到您希望能够点击的UITextView 。 您正在将UITapGestureRecognizer添加到ViewControllerview 。 这就是为什么演员让你陷入困境。 你正试图将一个UIView为一个UITextView

 let tapGesture = UITapGestureRecognizer(target: self, action: #selector(textTapped)) tapGesture.numberOfTapsRequired = 1 myTextView.addGestureRecognizer(tapGesture) 

技术上的textTapped()是一个可选的types( UIView! ),可能是nil ,但似乎不太可能你的textTapped()将被称为它没有设置。 同样的, layoutManager的types是NSLayoutManager! 。 为了安全起见,Swift的方法是:

 guard let textView = recognizer.view as? UITextView, let layoutManager = textView.layoutManager else { return } // code using textView and layoutManager goes here 

事实上,如果你这样写了,你就不会崩溃,因为UIViewUITextView的条件转换不会成功。

为了使这一切工作,然后将属性添加到您将在textTapped例程中提取的属性的string:

 var beginning = NSMutableAttributedString(string: "To the north you see a ") var attrs = [NSFontAttributeName: UIFont.systemFontOfSize(19.0), "idnum": "1", "desc": "old building"] var condemned = NSMutableAttributedString(string: "condemned building", attributes: attrs) beginning.appendAttributedString(condemned) attrs = [NSFontAttributeName: UIFont.systemFontOfSize(19.0), "idnum": "2", "desc": "lake"] var lake = NSMutableAttributedString(string: " on a small lake", attributes: attrs) beginning.appendAttributedString(lake) myTextView.attributedText = beginning 

以下是全文:

 @objc func textTapped(recognizer: UITapGestureRecognizer) { guard let textView = recognizer.view as? UITextView, let layoutManager = textView.layoutManager else { return } var location: CGPoint = recognizer.locationInView(textView) location.x -= textView.textContainerInset.left location.y -= textView.textContainerInset.top /* Here is what the Documentation looks like : Returns the index of the character falling under the given point, expressed in the given container's coordinate system. If no character is under the point, the nearest character is returned, where nearest is defined according to the requirements of selection by touch or mouse. This is not simply equivalent to taking the result of the corresponding glyph index method and converting it to a character index, because in some cases a single glyph represents more than one selectable character, for example an fi ligature glyph. In that case, there will be an insertion point within the glyph, and this method will return one character or the other, depending on whether the specified point lies to the left or the right of that insertion point. In general, this method will return only character indexes for which there is an insertion point (see next method). The partial fraction is a fraction of the distance from the insertion point logically before the given character to the next one, which may be either to the right or to the left depending on directionality. */ var charIndex = layoutManager.characterIndexForPoint(location, inTextContainer: textView.textContainer, fractionOfDistanceBetweenInsertionPoints: nil) guard charIndex < textView.textStorage.length else { return } var range = NSRange(location: 0, length: 0) if let idval = textView.attributedText?.attribute("idnum", atIndex: charIndex, effectiveRange: &range) as? NSString { print("id value: \(idval)") print("charIndex: \(charIndex)") print("range.location = \(range.location)") print("range.length = \(range.length)") let tappedPhrase = (textView.attributedText.string as NSString).substringWithRange(range) print("tapped phrase: \(tappedPhrase)") var mutableText = textView.attributedText.mutableCopy() as NSMutableAttributedString mutableText.addAttributes([NSForegroundColorAttributeName: UIColor.redColor()], range: range) textView.attributedText = mutableText } if let desc = textView.attributedText?.attribute("desc", atIndex: charIndex, effectiveRange: &range) as? NSString { print("desc: \(desc)") } } 

对于Swift 3.0或以上

添加点击手势到UITextView

 let tapGesture = UITapGestureRecognizer(target: self, action: #selector(tapOnTextView(_:))) textView.addGestureRecognizer(tapGesture) 

添加tap处理方法

 @objc private final func tapOnTextView(_ tapGesture: UITapGestureRecognizer){ let point = tapGesture.location(in: textView) if let detectedWord = getWordAtPosition(point) { } } 

从点得到的话

 private final func getWordAtPosition(_ point: CGPoint) -> String?{ if let textPosition = textView.closestPosition(to: point) { if let range = textView.tokenizer.rangeEnclosingPosition(textPosition, with: .word, inDirection: 1) { return textView.text(in: range) } } return nil}