【问题标题】:How to show cursor in NSTextView click location - MacOS如何在 NSTextView 单击位置显示光标 - MacOS
【发布时间】:2021-01-08 09:04:16
【问题描述】:

我正在开发一个 macOS 应用程序。我想编写一个代码,在NSTextView 的点击位置上显示光标。于是我在StackOverFlow中搜索,发现the following code for iOS

@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)
            }
        }
    }
}

所以,要将代码从 iOS 转换为 macOS,我可以:

  • UITapGestureRecognizer 更改为NSClickGestureRecognizer
  • textView.becomeFirstResponder() 更改为textView.window?.makeFirstResponder(textView)

问题是:

我无法将方法 .closestPosition.textRange.offset 转换为 macOS,因为它们仅在 UIKit 中可用,并且它们返回 UIKit 值,例如 UITextPositionUITextRange

最小可重现示例

要重现问题,只需创建一个基于文档的 Cocoa 应用程序(macOS),并添加一个 Scrollable TextView,那么代码将是:

import Cocoa

class ViewController: NSViewController, NSGestureRecognizerDelegate {

    @IBOutlet var textView: NSTextView!

    override func viewDidLoad() {
        super.viewDidLoad()
                
        // Set tap gesture
        let singleClickGesture = NSClickGestureRecognizer(target: self, action: #selector(singleClickGesture(_:)))
        singleClickGesture.numberOfClicksRequired = 1 // single
        singleClickGesture.delegate = self
        textView.addGestureRecognizer(singleClickGesture)
        // create attributed string
        let myAttrString = NSMutableAttributedString(string: "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.")
        // Write it to the Text View
        textView.textStorage?.append(myAttrString)
    }
    
    @objc func singleClickGesture(_ recognizer: NSClickGestureRecognizer) {
        // Show cursor and set it to position on tapping
        if recognizer.state == .ended {
            textView.isEditable = true
            textView.window?.makeFirstResponder(textView)

        // Comment the next 9 lines to see the problem.
        // TextView is not responding correctly to mouse clicks.
        // The next lines fixes the problem for UIKit (iOS),
        // but I couldn't make equivalent code for Cocoa (macOS).
            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)
                }
            }
        }
    }

}

解决方案?

【问题讨论】:

  • “在 NSTextView 的点击位置显示光标”是什么意思?
  • 因为我正在修改 NSClickGestureRecognizer,所以光标不会移动到我在 NSTextView 中点击的位置,它会一直显示在文本视图的末尾
  • 我发布了一个最小的可重现示例
  • 我的点击识别器中有更多代码(比如确定点击的段落和行),但我没有在上面的示例中编写它,因为它离题了。

标签: swift macos


【解决方案1】:

给你:

@objc func singleClickGesture(_ recognizer: NSClickGestureRecognizer) {
    // Show cursor and set it to position on tapping
    print("click \(String(describing: NSApp.currentEvent))")
    if recognizer.state == .ended {
        textView.isEditable = true
        if let window = textView.window, window.makeFirstResponder(textView) {
            let location = recognizer.location(in: textView)
            let position = textView.characterIndexForInsertion(at: location)
            textView.selectedRange = NSMakeRange(position, 0)
        }
    }
}

【讨论】:

  • 请您完成您的出色解决方案。该函数现在将光标移动到插入点,但是如果您双击,它不会选择单词,如果您三次单击,它不会选择整个文本。
  • 我认为 NSClickGestureRecognizer 不是您要完成的任务的正确解决方案。
  • 谢谢@Willeke,你还有什么推荐的吗?
  • 你想要完成什么?
  • 我想知道被点击的行的样式(属性),所以我必须使用点击手势识别器来识别点击位置,然后我才能确定该行/段落的属性。这就是我尝试使用 NSClickGestureRecognizer 的原因
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-05-06
  • 1970-01-01
  • 2019-06-14
  • 2022-12-06
  • 2019-03-13
相关资源
最近更新 更多