Swift - Textview 识别点击的单词不起作用
Swift - Textview Identify Tapped Word Not Working
老用户,第一次发帖,所以如果我在提出问题时有任何错误,我深表歉意。我已经为此工作了几个小时,我决定是时候请教专家了。我还搜索了 "answered" 和工作中的每个类似问题,这让我相信它们已经过时了。
我正在尝试从稍后将在代码中使用的 UITextview 中获取点击的单词。比如在文本视图中有一段文字:
"The initial return on time investment is much smaller, due to him trading his upfront cost for sweat-equity in the company, but the potential long-term payout is much greater"。
我希望能够点击一个词,例如'investment'和运行它通过另一个函数来定义它。但是简单地点击这个词,程序就会崩溃,而且我没有收到被点击的词。
我实现了点击手势识别器:
let tap = UITapGestureRecognizer(target: self, action: #selector(tapResponse(_:)))
tap.delegate = self
tvEditor.addGestureRecognizer(tap)
然后写函数:2
func tapResponse(recognizer: UITapGestureRecognizer) {
let location: CGPoint = recognizer.locationInView(tvEditor)
let position: CGPoint = CGPointMake(location.x, location.y)
let tapPosition: UITextPosition = tvEditor.closestPositionToPoint(position)!
let textRange: UITextRange = tvEditor.tokenizer.rangeEnclosingPosition(tapPosition, withGranularity: UITextGranularity.Word, inDirection: 1)!
let tappedWord: String = tvEditor.textInRange(textRange)!
print("tapped word : %@", tappedWord)
}
理想情况下,这应该从 Textview 的点击部分获取 location,通过获取 .x & 获取 position。 y,然后在最接近 position 的点查看 Textview,找到 Range 包含粒度的位置(到 return 这个词),并将内容设置为字符串,我目前只是将其打印到控制台。然而,在点击这个词时,我收到了这个崩溃。3
连同“致命错误:在打开可选值时意外发现 nil” 在控制台中。
如有任何帮助,我们将不胜感激。我可能只是遗漏了一些简单的东西,或者它可能会复杂得多。
- 每当在单词之间的空格处接收到点击时,由
TextView
编辑的tapPosition return可以为零nil
。
- Swift 有一个名为 optional
?
的新运算符,它告诉编译器该变量可能具有 nil 值。如果变量名后不使用?
表示变量永远不能有nil值。
- 在 Swift 中,使用
!
运算符意味着您强制编译器从可选变量中强制提取值。所以,在那种情况下,如果变量的值为 nil,它会在强制时崩溃。
所以,实际发生的是
- 您正在创建变量
let tapPosition: UITextPosition
,let textRange: UITextRange
和 let tappedWord: String
不是可选的
- return方法的类型
myTextView.closestPositionToPoint(position)
、tvEditor.textInRange(textRange)
是可选变量UITextPosition?
、String?
- 将可选变量的值赋给非可选变量需要
!
- 方法是 returning
nil
并且您强制它获取值 !
导致 CRASH
你能做什么
在强制任何可选变量之前,只需确保它具有使用
的一些值
if variable != nil
{
print(variable!)
}
正确的方法是
func tapResponse(recognizer: UITapGestureRecognizer) {
let location: CGPoint = recognizer.locationInView(myTextView)
let position: CGPoint = CGPointMake(location.x, location.y)
let tapPosition: UITextPosition? = myTextView.closestPositionToPoint(position)
if tapPosition != nil {
let textRange: UITextRange? = myTextView.tokenizer.rangeEnclosingPosition(tapPosition!, withGranularity: UITextGranularity.Word, inDirection: 1)
if textRange != nil
{
let tappedWord: String? = myTextView.textInRange(textRange!)
print("tapped word : ", tappedWord)
}
}
}
Swift 3.0 答案 - 2016 年 7 月 1 日起工作
在我的 ViewDidLoad() 中 -
我使用了之前 VC 中的文本,所以我的变量 "theText" 已经声明了。我包含了一个已注明的示例字符串。
//Create a variable of the text you wish to attribute.
let textToAttribute = theText // or "This is sample text"
// Break your string in to an array, to loop through it.
let textToAttributeArray = textToAttribute.componentsSeparatedByString(" ")
// Define a variable as an NSMutableAttributedString() so you can append to it in your loop.
let attributedText = NSMutableAttributedString()
// Create a For - In loop that goes through each word your wish to attribute.
for word in textToAttributeArray{
// Create a pending attribution variable. Add a space for linking back together so that it doesn't looklikethis.
let attributePending = NSMutableAttributedString(string: word + " ")
// Set an attribute on part of the string, with a length of the word.
let myRange = NSRange(location: 0, length: word.characters.count)
// Create a custom attribute to get the value of the word tapped
let myCustomAttribute = [ "Tapped Word:": word]
// Add the attribute to your pending attribute variable
attributePending.addAttributes(myCustomAttribute, range: myRange)
print(word)
print(attributePending)
//append 'attributePending' to your attributedText variable.
attributedText.appendAttributedString(attributePending) ///////
print(attributedText)
}
textView.attributedText = attributedText // Add your attributed text to textview.
现在我们将添加一个点击手势识别器来注册点击。
let tap = UITapGestureRecognizer(target: self, action: #selector(HandleTap(_:)))
tap.delegate = self
textView.addGestureRecognizer(tap) // add gesture recognizer to text view.
现在我们在viewDidLoad()下声明一个函数
func HandleTap(sender: UITapGestureRecognizer) {
let myTextView = sender.view as! UITextView //sender is TextView
let layoutManager = myTextView.layoutManager //Set layout manager
// location of tap in myTextView coordinates
var location = sender.locationInView(myTextView)
location.x -= myTextView.textContainerInset.left;
location.y -= myTextView.textContainerInset.top;
// character index at tap location
let characterIndex = layoutManager.characterIndexForPoint(location, inTextContainer: myTextView.textContainer, fractionOfDistanceBetweenInsertionPoints: nil)
// if index is valid then do something.
if characterIndex < myTextView.textStorage.length {
// print the character index
print("Your character is at index: \(characterIndex)") //optional character index.
// print the character at the index
let myRange = NSRange(location: characterIndex, length: 1)
let substring = (myTextView.attributedText.string as NSString).substringWithRange(myRange)
print("character at index: \(substring)")
// check if the tap location has a certain attribute
let attributeName = "Tapped Word:" //make sure this matches the name in viewDidLoad()
let attributeValue = myTextView.attributedText.attribute(attributeName, atIndex: characterIndex, effectiveRange: nil) as? String
if let value = attributeValue {
print("You tapped on \(attributeName) and the value is: \(value)")
}
}
}
除了@AmitSingh 的回答,这是更新的Swift 3.0 版本:
func didTapTextView(recognizer: UITapGestureRecognizer) {
let location: CGPoint = recognizer.location(in: textView)
let position: CGPoint = CGPoint(x: location.x, y: location.y)
let tapPosition: UITextPosition? = textView.closestPosition(to: position)
if tapPosition != nil {
let textRange: UITextRange? = textView.tokenizer.rangeEnclosingPosition(tapPosition!, with: UITextGranularity.word, inDirection: 1)
if textRange != nil
{
let tappedWord: String? = textView.text(in: textRange!)
print("tapped word : ", tappedWord!)
}
}
}
其他代码和他的一样。
希望对您有所帮助!
老用户,第一次发帖,所以如果我在提出问题时有任何错误,我深表歉意。我已经为此工作了几个小时,我决定是时候请教专家了。我还搜索了 "answered" 和工作中的每个类似问题,这让我相信它们已经过时了。
我正在尝试从稍后将在代码中使用的 UITextview 中获取点击的单词。比如在文本视图中有一段文字:
"The initial return on time investment is much smaller, due to him trading his upfront cost for sweat-equity in the company, but the potential long-term payout is much greater"。
我希望能够点击一个词,例如'investment'和运行它通过另一个函数来定义它。但是简单地点击这个词,程序就会崩溃,而且我没有收到被点击的词。
我实现了点击手势识别器:
let tap = UITapGestureRecognizer(target: self, action: #selector(tapResponse(_:)))
tap.delegate = self
tvEditor.addGestureRecognizer(tap)
然后写函数:2
func tapResponse(recognizer: UITapGestureRecognizer) {
let location: CGPoint = recognizer.locationInView(tvEditor)
let position: CGPoint = CGPointMake(location.x, location.y)
let tapPosition: UITextPosition = tvEditor.closestPositionToPoint(position)!
let textRange: UITextRange = tvEditor.tokenizer.rangeEnclosingPosition(tapPosition, withGranularity: UITextGranularity.Word, inDirection: 1)!
let tappedWord: String = tvEditor.textInRange(textRange)!
print("tapped word : %@", tappedWord)
}
理想情况下,这应该从 Textview 的点击部分获取 location,通过获取 .x & 获取 position。 y,然后在最接近 position 的点查看 Textview,找到 Range 包含粒度的位置(到 return 这个词),并将内容设置为字符串,我目前只是将其打印到控制台。然而,在点击这个词时,我收到了这个崩溃。3
连同“致命错误:在打开可选值时意外发现 nil” 在控制台中。
如有任何帮助,我们将不胜感激。我可能只是遗漏了一些简单的东西,或者它可能会复杂得多。
- 每当在单词之间的空格处接收到点击时,由
TextView
编辑的tapPosition return可以为零nil
。 - Swift 有一个名为 optional
?
的新运算符,它告诉编译器该变量可能具有 nil 值。如果变量名后不使用?
表示变量永远不能有nil值。 - 在 Swift 中,使用
!
运算符意味着您强制编译器从可选变量中强制提取值。所以,在那种情况下,如果变量的值为 nil,它会在强制时崩溃。
所以,实际发生的是
- 您正在创建变量
let tapPosition: UITextPosition
,let textRange: UITextRange
和let tappedWord: String
不是可选的 - return方法的类型
myTextView.closestPositionToPoint(position)
、tvEditor.textInRange(textRange)
是可选变量UITextPosition?
、String?
- 将可选变量的值赋给非可选变量需要
!
- 方法是 returning
nil
并且您强制它获取值!
导致 CRASH
你能做什么
在强制任何可选变量之前,只需确保它具有使用
的一些值if variable != nil { print(variable!) }
正确的方法是
func tapResponse(recognizer: UITapGestureRecognizer) {
let location: CGPoint = recognizer.locationInView(myTextView)
let position: CGPoint = CGPointMake(location.x, location.y)
let tapPosition: UITextPosition? = myTextView.closestPositionToPoint(position)
if tapPosition != nil {
let textRange: UITextRange? = myTextView.tokenizer.rangeEnclosingPosition(tapPosition!, withGranularity: UITextGranularity.Word, inDirection: 1)
if textRange != nil
{
let tappedWord: String? = myTextView.textInRange(textRange!)
print("tapped word : ", tappedWord)
}
}
}
Swift 3.0 答案 - 2016 年 7 月 1 日起工作
在我的 ViewDidLoad() 中 -
我使用了之前 VC 中的文本,所以我的变量 "theText" 已经声明了。我包含了一个已注明的示例字符串。
//Create a variable of the text you wish to attribute.
let textToAttribute = theText // or "This is sample text"
// Break your string in to an array, to loop through it.
let textToAttributeArray = textToAttribute.componentsSeparatedByString(" ")
// Define a variable as an NSMutableAttributedString() so you can append to it in your loop.
let attributedText = NSMutableAttributedString()
// Create a For - In loop that goes through each word your wish to attribute.
for word in textToAttributeArray{
// Create a pending attribution variable. Add a space for linking back together so that it doesn't looklikethis.
let attributePending = NSMutableAttributedString(string: word + " ")
// Set an attribute on part of the string, with a length of the word.
let myRange = NSRange(location: 0, length: word.characters.count)
// Create a custom attribute to get the value of the word tapped
let myCustomAttribute = [ "Tapped Word:": word]
// Add the attribute to your pending attribute variable
attributePending.addAttributes(myCustomAttribute, range: myRange)
print(word)
print(attributePending)
//append 'attributePending' to your attributedText variable.
attributedText.appendAttributedString(attributePending) ///////
print(attributedText)
}
textView.attributedText = attributedText // Add your attributed text to textview.
现在我们将添加一个点击手势识别器来注册点击。
let tap = UITapGestureRecognizer(target: self, action: #selector(HandleTap(_:)))
tap.delegate = self
textView.addGestureRecognizer(tap) // add gesture recognizer to text view.
现在我们在viewDidLoad()下声明一个函数
func HandleTap(sender: UITapGestureRecognizer) {
let myTextView = sender.view as! UITextView //sender is TextView
let layoutManager = myTextView.layoutManager //Set layout manager
// location of tap in myTextView coordinates
var location = sender.locationInView(myTextView)
location.x -= myTextView.textContainerInset.left;
location.y -= myTextView.textContainerInset.top;
// character index at tap location
let characterIndex = layoutManager.characterIndexForPoint(location, inTextContainer: myTextView.textContainer, fractionOfDistanceBetweenInsertionPoints: nil)
// if index is valid then do something.
if characterIndex < myTextView.textStorage.length {
// print the character index
print("Your character is at index: \(characterIndex)") //optional character index.
// print the character at the index
let myRange = NSRange(location: characterIndex, length: 1)
let substring = (myTextView.attributedText.string as NSString).substringWithRange(myRange)
print("character at index: \(substring)")
// check if the tap location has a certain attribute
let attributeName = "Tapped Word:" //make sure this matches the name in viewDidLoad()
let attributeValue = myTextView.attributedText.attribute(attributeName, atIndex: characterIndex, effectiveRange: nil) as? String
if let value = attributeValue {
print("You tapped on \(attributeName) and the value is: \(value)")
}
}
}
除了@AmitSingh 的回答,这是更新的Swift 3.0 版本:
func didTapTextView(recognizer: UITapGestureRecognizer) {
let location: CGPoint = recognizer.location(in: textView)
let position: CGPoint = CGPoint(x: location.x, y: location.y)
let tapPosition: UITextPosition? = textView.closestPosition(to: position)
if tapPosition != nil {
let textRange: UITextRange? = textView.tokenizer.rangeEnclosingPosition(tapPosition!, with: UITextGranularity.word, inDirection: 1)
if textRange != nil
{
let tappedWord: String? = textView.text(in: textRange!)
print("tapped word : ", tappedWord!)
}
}
}
其他代码和他的一样。
希望对您有所帮助!