我正在实现一个显示完整问题的屏幕
例如:
“一周的第一天是……”
当用户触摸这些点时,会出现警报,并允许用户输入答案以提交并用他的答案替换这些点
我的步骤是:
1。我通过以下方式生成了点的范围:
func getRangesOfMissingWords(by missingWord: String = completePlace) -> [(answer: String, range: NSRange)]? {
let body: NSString = theQuestionBody.text as NSString
var ranges : [(answer: String, range: NSRange)] = []
var searchRange = NSRange(location: 0, length: body.length)
while searchRange.location < body.length {
searchRange.length = body.length - searchRange.location
let foundRange = self.getRangeOf(word: missingWord, in: searchRange)
if foundRange != nil {
ranges.append((answer: missingWord, range: foundRange!))
searchRange.location = foundRange!.location + foundRange!.length
}
else {
break
}
}
if ranges.isEmpty == false {
return ranges
}
else {
return nil
}
}
然后
2.围绕缺失的单词范围生成框架:
func createAnswersFrames(from ranges: [(answer: String, range: NSRange)]) {
var frames : [WordFrame] = []
for range in ranges {
let pos2 = self.theQuestionBody.position(from: self.theQuestionBody.beginningOfDocument, offset: (range.range.location + (range.range.length - 1)))
let pos1 = self.theQuestionBody.position(from: self.theQuestionBody.beginningOfDocument, offset: range.range.location)
print("pos1 : \(pos1.debugDescription)")
print("pos2 : \(pos2.debugDescription)")
let textRange : UITextRange = self.theQuestionBody.textRange(from: pos1!, to: pos2!)!
let frame: CGRect = self.theQuestionBody.firstRect(for: textRange)
frames.append(WordFrame(rect: frame))
}
self.missingWordsFrames = frames
}
和
3.为UITextView添加了一个UITapGestureRecognizer
let sigleTap : UITapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(handleTap(tapRecognizer:)))
theQuestionBody.addGestureRecognizer(sigleTap)
4.并在点击的观察者中
func handleTap(tapRecognizer: UITapGestureRecognizer) {
guard let ranges = self.missingWordsRanges else {
return
}
self.createAnswersFrames(from: ranges)
let touchPoint = tapRecognizer.location(in: theQuestionBody)
if self.missingWordsFrames.count > 0 {
for (index,frame) in self.missingWordsFrames.enumerated() {
frame.isSelected = false
let validFrame = frame.rect
if (validFrame.contains(touchPoint)) {
frame.isSelected = true
let alertTitle = Helper.getSerroundingText(of: self.missingWordsRanges![index].range, from: self.question.text)
let alert = UIAlertController(title: alertTitle , message:"", preferredStyle: .alert)
alert.addTextField { (textField) in
textField.placeholder = "Complete..."
}
alert.addAction(UIAlertAction(title: "OK", style: .default, handler: { [weak alert] (_) in
let textField = alert!.textFields![0]
textField.becomeFirstResponder()
let answer = textField.text
if answer != "" {
self.submitAnswer(answer!)
}
}))
self.present(alert, animated: true, completion: nil)
break
}
}
}
}
问题是,第一次出现 View 时,框架工作正常,但是当用户插入包含大量字符的答案时,其余文本将放置在新行中,框架就不起作用了。那么就可以正常工作了。
Example
"The x is a .......... . And the y is .........."
answer -> "SomeLongWordAnswer"
"The x is a SomeLongWordAnswer . And the y is
.........."
这里第二个点的框架保持在第一行!
最佳答案
我通过删除框架改变了实现它的方式,并依赖于 UITextViewDelegate
textViewDidChangeSelection
func textViewDidChangeSelection(_ textView: UITextView) {
UIMenuController.shared.isMenuVisible = false
if let missingWordRanges = self.missingWordsRanges {
for (index,range) in missingWordRanges.enumerated() {
if range.range == textView.selectedRange {
let alertTitle = Helper.getSerroundingText(of: self.missingWordsRanges![index].range, from: self.question.text)
let alert = UIAlertController(title: alertTitle , message:"", preferredStyle: .alert)
alert.addTextField { (textField) in
textField.placeholder = "Complete..."
}
alert.addAction(UIAlertAction(title: "OK", style: .default, handler: { [weak alert] (_) in
let textField = alert!.textFields![0] // Force unwrapping because we know it exists.
textField.becomeFirstResponder()
let answer = textField.text
if answer != "" {
self.submit(answer!, in: index) // cann't press ok if not submitted with an answer so force rapping is okay
}
}))
self.present(alert, animated: true, completion: nil)
return
}
}
}
}
然后出现的问题是,当选择更改时会调用此方法,而在 iPhone 中,通过双击或长按来更改选择
所以我更新了我的手势
let sigleTap : UITapGestureRecognizer = UITapGestureRecognizer.init(target: self, action: #selector(didRecieveGestureOnText(recognizer:)))
theQuestionBody.addGestureRecognizer(sigleTap)
func didRecieveGestureOnText(recognizer: UIGestureRecognizer) {
let textView : UITextView = recognizer.view as! UITextView
let location = recognizer.location(in: self.theQuestionBody)
let tapPosition = textView.closestPosition(to: location)
let textRange = textView.tokenizer.rangeEnclosingPosition(tapPosition!, with: UITextGranularity.word, inDirection: UITextLayoutDirection.right.rawValue)
self.theQuestionBody.selectedTextRange = textRange
}
所以通过这一行self.theQuestionBody.selectedTextRange = textRange
将触发textViewDidChangeSelection
并且一切都按预期工作
关于ios - 当用户在 UITextView 中选择特定单词时,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46873357/