链接可编辑的NSTextView(如Apple的Notes)

时间:2018-08-15 17:59:26

标签: swift cocoa nsattributedstring nstextview

我有一个NSTextView,它最初像这样设置为只读:

taskDescription.isEditable = false

我在viewDidLoad()上这样设置了点击手势识别器,以便用户单击该字段时将其设置为可编辑状态。

override func viewDidLoad() {
  super.viewDidLoad()

  let clickGesture = NSClickGestureRecognizer(target: self, action: #selector(setDescriptionEditState))
  clickGesture.numberOfClicksRequired = 1
  taskDescription.addGestureRecognizer(clickGesture)
}

这是单击时调用的函数:

@objc func setDescriptionEditState(){
  //Make it editable
  taskDescription.isEditable = true

  //Don't show automatic link detect while editing (I want plain text)
  taskDescription.checkTextInDocument(nil)

  //Put the cursor in the NSTextView  
  taskDescription.window?.makeFirstResponder(taskDescription)
}

然后,当我将NSAttributedString加载到其中并带有链接时,它显示的很好:

NSTextView with a link

最后,我为NSTextView实现了这个委托方法:

func textView(_ textView: NSTextView, clickedOnLink link: Any, at charIndex: Int) -> Bool {
  print(link) //<-- Never called
}

正在发生的情况是调用clickGesture而不是单击链接。我知道这是因为,如果我手动将NSTextView设置为isEditable = false,则链接可以正常工作。

如何允许发生链接单击,同时仍然允许用户单击NSTextView将其切换到编辑模式?

---更新---

我将NSTextView的内容设置为NSAttributedString。登录到控制台后,它看起来像这样:

I want {
    NSColor = "...";
    NSFont = "...";
}a big link{
    NSColor = "...";
    NSFont = "...";
    NSLink = "google.com";
} here.{
    NSColor = "...";
    NSFont = "...";
}

因此,链接是用NSLink指定的。

1 个答案:

答案 0 :(得分:0)

关键是要覆盖功能“ touchesBegan”并实现自己的逻辑。

override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
    let touch = touches.first
    guard let location = touch?.location(in: self.view) else { return }
    if !popupContainer.frame.contains(location) {
        goodTouch = true
    } else {
        goodTouch = false
    }
}

将变量“ goodTouch”建立为类属性。然后,您可以在相关功能的开头检查此变量的状态,然后从那里适当地路由应用程序。 (这是我写的一个iOS项目专门改编的,但对于Cocoa应该是相同的)。确保已实现,请在检查“ goodTouch”变量以准备进行下一轮触摸后将其重置为false。

编辑 我认为这是对您的特定示例的更合适的答复,但是我不想从上面删除代码:

override func mouseDown(with event: NSEvent) {
    let textField = NSTextField() //this is for demo only...reference your actual object

    let location = event.locationInWindow
    let cgPoint = CGPoint(x: location.x, y: location.y)
    if textField.bounds.contains(cgPoint) {
        //fire the link here, over ride the click gesture recognizer
    } else {
        //change the editable style of the text field
    }
}