在Swift中从UITextView获取点击的单词 [英] Get tapped word from UITextView in Swift
问题描述
我知道这个问题已经在Objective-C中解决了,但是我在Swift中还没有看到任何解决方案.我试图从转换解决方案代码发布,但出现错误:
I know that this problem has been solved in Objective-C, but I haven't seen any solution to it in Swift. I have tried to convert the solution code from this post, but I'm getting errors:
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)
}
}
我认为问题出在这一行(请参见错误此处):
I think the problem is in this line (see error here):
var textView: UITextView = recognizer.view as UITextView
...我是根据以下这一行从Objective-C转换而来的:
... which I have converted from Objective-C based on this line:
UITextView *textView = (UITextView *)recognizer.view;
最后,对于如何调用此函数,我也有疑问.据我了解,该函数应传递给viewDidLoad()中的Selector,如下所示:
Finally, I am also in doubt about how this function should be called. As I understand it, the function should be passed to a Selector in viewDidLoad(), like this:
let aSelector: Selector = "textTapped:"
let tapGesture = UITapGestureRecognizer(target: self, action: aSelector)
tapGesture.numberOfTapsRequired = 1
view.addGestureRecognizer(tapGesture)
因为我遇到了前面提到的错误,所以不确定是否可以使用.但是我在想,我还需要将textTapped函数(识别器)中的参数传递到选择器中.但是,我读到您只能传递函数,而不能传递任何参数.
Because I'm getting the before mentioned error, I'm not sure if it would work. But I'm thinking that I would need to pass the parameter in the textTapped function (recognizer) into the Selector as well. However, I've read that you can only pass the function and not any parameters.
推荐答案
您需要将UITapGestureRecognizer
添加到要点击的UITextView
中.您当前正在将UITapGestureRecognizer
添加到ViewController
的view
中.这就是演员阵容让您陷入困境的原因.您正在尝试将UIView
强制转换为UITextView
.
You need to add the UITapGestureRecognizer
to the UITextView
that you want to be able to tap. You are presently adding the UITapGestureRecognizer
to your ViewController
's view
. That is why the cast is getting you into trouble. You are trying to cast a UIView
to a UITextView
.
let tapGesture = UITapGestureRecognizer(target: self, action: #selector(textTapped))
tapGesture.numberOfTapsRequired = 1
myTextView.addGestureRecognizer(tapGesture)
从技术上讲,recognizer.view
是可选类型(UIView!
),可能是nil
,但是您的textTapped()
似乎没有被称为未设置的类型.同样,layoutManager
的类型为NSLayoutManager!
.为了安全起见,Swift的方法是:
Technically recognizer.view
is an optional type (UIView!
) and could be nil
, but it seems unlikely that your textTapped()
would be called it that wasn't set. Likewise, the layoutManager
is of type NSLayoutManager!
. To be on the safe side though, the Swift way to do this is:
guard let textView = recognizer.view as? UITextView, let layoutManager = textView.layoutManager else {
return
}
// code using textView and layoutManager goes here
实际上,如果您以此方式编写,则不会崩溃,因为UIView
到UITextView
的条件强制转换不会成功.
In fact, if you had written it this way, you wouldn't have crashed because the conditional cast of the UIView
to UITextView
would not have succeeded.
然后,要使所有这些工作正常进行,请将属性添加到将在textTapped例程中提取的属性字符串中:
To make this all work then, add attributes to your attributed string that you will extract in your textTapped routine:
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
这是完整的textTapped
:
@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中从UITextView获取点击的单词的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!