如何知道用户点击了TextView的哪一行 [英] How to know which line of a TextView the user has tapped on

查看:58
本文介绍了如何知道用户点击了TextView的哪一行的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在构建一个具有多行文本编辑器(UIKit中为UITextView,而SwiftUI中为TextEditor)的应用程序.当用户点击多行文本的任何一行时,我应该知道那是哪一行,因此我可以打印该行或执行其他任何任务.

I'm building an app that has a multi-line text editor (UITextView in UIKit, and TextEditor in SwiftUI). When the user tap on any line of the multi-line text, I should know which line is that, so I can print that line or do any other task.

是否有办法知道用户点击了UITextView的哪一行(使用 textViewDidChangeSelection 委托函数或其他方法)?

Is there a way to know which line of a UITextView the user has tapped on (using textViewDidChangeSelection delegate function or anything else)?

我当时正在考虑将整个文本存储在一个数组中(每行是一个元素),并连续更新该数组,但是问题仍然存在,我如何知道应该点击哪一行来相应地更新数组?

I was thinking of storing the whole text in an Array (each line is an element), and updating the array continuously, but the problem still exists, how shall I know which line has been tapped on to update the array accordingly?

注意:我正在使用属性字符串为每行赋予不同的样式.

Note: I'm using Attributed Strings to give every line different styling.

推荐答案

Swift 5 UIKit解决方案:

尝试向textView添加轻击手势并检测点击的单词:

Try to add tap gesture to textView and detect the word tapped:

let textView: UITextView = {
let tv = UITextView()
tv.text = "ladòghjòdfghjdaòghjjahdfghaljdfhgjadhgf ladjhgf dagf adjhgf adgljdgadsjhladjghl dgfjhdjgh jdahgfljhadlghal dkgjafahd fgjdsfgh adh"
tv.textColor = .black
tv.font = .systemFont(ofSize: 16, weight: .semibold)
tv.textContainerInset = UIEdgeInsets(top: 40, left: 0, bottom: 0, right: 0)
tv.translatesAutoresizingMaskIntoConstraints = false
    
return tv
}()

在那之后,在viewDidLoad中设置点击手势和约束:

After that in viewDidLoad set tap gesture and constraints:

let tap = UITapGestureRecognizer(target: self, action: #selector(tapResponse(recognizer:)))
textView.addGestureRecognizer(tap)
    
view.addSubview(textView)
textView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor).isActive = true
textView.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor).isActive = true
textView.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor).isActive = true
textView.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor).isActive = true

现在调用该函数以检测单词:

now call the function to detect word:

@objc func tapResponse(recognizer: UITapGestureRecognizer) {
    let location: CGPoint = recognizer.location(in: textView)
    let position: CGPoint = CGPoint(x: location.x, y: location.y)
    guard let position2 = textView.closestPosition(to: position) else { return }
    let tapPosition: UITextPosition = position2
    guard let textRange: UITextRange = textView.tokenizer.rangeEnclosingPosition(tapPosition, with: UITextGranularity.word, inDirection: UITextDirection(rawValue: 1)) else {return}
    
    let tappedWord: String = textView.text(in: textRange) ?? ""
    print("tapped word:", tappedWord)
}

使用属性字符串是同一回事.

with Attributed Strings it is the same thing.

更新

添加此功能以检测行:

@objc func didTapTextView(recognizer: UITapGestureRecognizer) {
    if recognizer.state == .recognized {
        let location = recognizer.location(ofTouch: 0, in: textView)

        if location.y >= 0 && location.y <= textView.contentSize.height {
            guard let font = textView.font else {
                return
            }

            let line = Int((location.y - textView.textContainerInset.top) / font.lineHeight) + 1
            print("Line is \(line)")
        }
    }
}

别忘了在点击时更改被调用的功能

don't forget to change called function on tap:

let tap = UITapGestureRecognizer(target: self, action: #selector(didTapTextView(recognizer:)))

编辑以在TAP上显示光标并设置其位置

在didTapTextView函数中显示光标在点击位置添加结束状态到识别器,设置文本视图是可编辑的并成为第一响应者,这是您的didTapTextView函数的样子:

to show the cursor on tap location add ended state to recognizer in didTapTextView function set text view is editable and become first responder, this is your didTapTextView function look like:

@objc func didTapTextView(recognizer: UITapGestureRecognizer) {
    
    if recognizer.state == .ended {
           textView.isEditable = true
           textView.becomeFirstResponder()

           let location = recognizer.location(in: textView)
           if let position = textView.closestPosition(to: location) {
               let uiTextRange = textView.textRange(from: position, to: position)

               if let start = uiTextRange?.start, let end = uiTextRange?.end {
                   let loc = textView.offset(from: textView.beginningOfDocument, to: position)
                   let length = textView.offset(from: start, to: end)

                   textView.selectedRange = NSMakeRange(loc, length)
               }
           }
       }
    
    if recognizer.state == .recognized {
        let location = recognizer.location(ofTouch: 0, in: textView)

        if location.y >= 0 && location.y <= textView.contentSize.height {
            guard let font = textView.font else {
                return
            }

            let line = Int((location.y - textView.textContainerInset.top) / font.lineHeight) + 1
            print("Line is \(line)")
        }
    }
}

在我的示例中,我将光标颜色设置为绿色以使其更加可见,为此它设置了textView着色颜色(我在TextView属性文本上添加了该颜色):

in my example I set cursor color to green to make it much visible, to do it set textView tint color (I added on TextView attributed text):

let textView: UITextView = {
    let tv = UITextView()
    
    tv.textContainerInset = UIEdgeInsets(top: 40, left: 0, bottom: 0, right: 0)
    tv.translatesAutoresizingMaskIntoConstraints = false
    tv.tintColor = .green // cursor color
    
    let attributedString = NSMutableAttributedString(string: "ladòghjòdfghjdaòghjjahdfghaljdfhgjadhgf ladjhgf dagf adjhgf adgljdgadsjhladjghl", attributes: [.font: UIFont.systemFont(ofSize: 20, weight: .regular), .foregroundColor: UIColor.red])
    attributedString.append(NSAttributedString(string: " dgfjhdjgh jdahgfljhadlghal dkgjafahd fgjdsfgh adh jsfgjskbfgfs gsfjgbjasfg ajshg kjshafgjhsakhg shf", attributes: [.font: UIFont.systemFont(ofSize: 20, weight: .bold), .foregroundColor: UIColor.black]))
    
    tv.attributedText = attributedString
    
    return tv
}()

这是结果:

这篇关于如何知道用户点击了TextView的哪一行的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆