ios - 当用户在 UITextView 中选择特定单词时

标签 ios swift uitextview

我正在实现一个显示完整问题的屏幕

例如:

“一周的第一天是……”

当用户触摸这些点时,会出现警报,并允许用户输入答案以提交并用他的答案替换这些点

我的步骤是:

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

的委托(delegate)方法
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)

以及基于 hris.to 的手势处理程序answer

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/

相关文章:

swift - 如何像在 App Store 应用程序(产品描述 TextView )中一样在 Apple TV 上添加可扩展的 TextView

ios - 如果 TableView 没有结果显示 "no results"标签(2 个计数)

ios - 在从 Environment.SpecialFolder.LocalApplicationData 加载的文件上设置 BaseUrl

ios - Swift 4 - Alamofire 4 上传带参数的图片

ios - 隐形按钮对点击没有反应

string - Swift - 从字符串中提取 double 值

ios - 以编程方式在 collectionView swift 中无限滚动

iphone - 组合页面控件+ ScrollView (包括 ImageView )+ TextView

ios - 当没有文本时,textView.text 属性不为 nil

ios - 在 UITextView 上启用滚动