在 NSTextView 中查找光标的坐标

Find cursor's coordinates in NSTextView

我有 NSTextView 个垂直堆叠的包装实例,例如:

The quick brown fox
jumps over the lazy dog
Jackdaws love my big
sphinx of quartz

我需要用 up/down 箭头在它们之间移动。例如,当光标位于“lazy”中的 l 之后并且用户按下向下箭头时,光标应该跳到 y[=36= 之后] 在“我的”中——就像这些句子在同一个文本视图中一样。

默认情况下,当光标位于最后换行时按下向下箭头,文本视图会将其移动到该行的末尾。虽然我可以在 NSTextViewDelegate 中使用 textView(_:doCommandBy:) 来检测“向下箭头”选择器并覆盖默认行为,但存在两个问题:

  1. 我可以通过 selectedRanges 属性 获取它的位置然后检查这个位置之后的换行符来确定光标是否在最后一行,但是它无法知道它是否在最后 wrapped 行,即靠近当前文本视图的边界。

  2. 我需要知道光标的 X 坐标才能将其放置在另一个文本视图中大致相同的 X 坐标处(字体不一定是固定宽度的,所以我不能取决于字符数)。

我想这两个问题都可以通过 NSLayoutManager 来解决,但我无法理解所有可用的方法。

事实证明它相对容易,这是我所做的(示例在 C# 中)。首先,boundingRect(forGlyphRange:in:)获取光标在当前视图中的位置:

var cursorLocation = new NSRange(CurrentTextView.SelectedRange.Location, 0);
var cursorCoordinates = CurrentTextView.LayoutManager.BoundingRectForGlyphRange(cursorLocation, CurrentTextView.TextContainer).Location;

那么如果第二个文本视图在下方,插入点将在 Y 轴上的 0 处:

var insertionPoint = new CGPoint(cursorCoordinates.X, 0);

而如果是上面,则应使用另一个视图的高度(减1,否则得到的字符索引不正确,光标将放在行尾):

var insertionPoint = new CGPoint(cursorCoordinates.X, AnotherTextView.Bounds.Size.Height - 1);

获取插入点后,另一个视图需要成为第一响应者,然后characterIndexForInsertion(at:)完成工作:

Window.MakeFirstResponder(AnotherTextView);
var index = AnotherTextView.CharacterIndex(insertionPoint);
AnotherTextView.SelectedRange = new NSRange(index, 0);