在 NSTextField 中查找 rect/position 个单词
Find rect/position of words in NSTextField
我有一个 NSTextField,里面有一句话。我想为句子中的每个单词找到一个矩形(理想情况下)或位置以在这些位置(在 NSTextField 之外)做事。
使用 NSLayoutManager.boundingRectForGlyphRange
在 NSTextView/UITextView 中执行此操作,但如果没有 NSTextView(和 UITextView)拥有的 NSLayoutManager,这似乎更具挑战性。
我在 NSTextField 中查找给定单词位置的最佳方法是什么?
它需要一个 barely-documented 位魔术和另一个完全未记录的位。这是 Objective-C 代码。抱歉,Swift 中没有它。
NSRect textBounds = [textField.cell titleRectForBounds:textField.bounds];
NSTextContainer* textContainer = [[NSTextContainer alloc] init];
NSLayoutManager* layoutManager = [[NSLayoutManager alloc] init];
NSTextStorage* textStorage = [[NSTextStorage alloc] init];
[layoutManager addTextContainer:textContainer];
[textStorage addLayoutManager:layoutManager];
textContainer.lineFragmentPadding = 2;
layoutManager.typesetterBehavior = NSTypesetterBehavior_10_2_WithCompatibility;
textContainer.containerSize = textBounds.size;
[textStorage beginEditing];
textStorage.attributedString = textField.attributedStringValue;
[textStorage endEditing];
NSUInteger count;
NSRectArray rects = [layoutManager rectArrayForCharacterRange:matchRange
withinSelectedCharacterRange:matchRange
inTextContainer:textContainer
rectCount:&count];
for (NSUInteger i = 0; i < count; i++)
{
NSRect rect = NSOffsetRect(rects[i], textBounds.origin.x, textBounds.origin.y);
rect = [textField convertRect:rect toView:self];
// do something with rect
}
typesetterBehavior
被记录在案 here。 lineFragmentPadding
是根据经验确定的。
根据您打算对矩形执行的具体操作,您可能希望传递 { NSNotFound, 0 }
作为所选字符范围。
为了提高效率,您通常希望保留文本对象而不是每次都实例化它们。您只需每次将文本容器的 containerSize
和文本存储的 attributedString
设置为适当的值。
根据 Ken Thomases 的回答。我为 Swift 4.2
做了改编
guard let textFieldCell = textField.cell,
let textFieldCellBounds = textFieldCell.controlView?.bounds else{
return
}
let textBounds = textFieldCell.titleRect(forBounds: textFieldCellBounds)
let textContainer = NSTextContainer()
let layoutManager = NSLayoutManager()
let textStorage = NSTextStorage()
layoutManager.addTextContainer(textContainer)
textStorage.addLayoutManager(layoutManager)
layoutManager.typesetterBehavior = NSLayoutManager.TypesetterBehavior.behavior_10_2_WithCompatibility
textContainer.containerSize = textBounds.size
textStorage.beginEditing()
textStorage.setAttributedString(textFieldCell.attributedStringValue)
textStorage.endEditing()
let rangeCharacters = (textFieldCell.stringValue as NSString).range(of: "string")
var count = 0
let rects: NSRectArray = layoutManager.rectArray(forCharacterRange: rangeCharacters,
withinSelectedCharacterRange: rangeCharacters,
in: textContainer,
rectCount: &count)!
for i in 0...count {
var rect = NSOffsetRect(rects[i], textBounds.origin.x, textBounds.origin.y)
rect = textField.convert(rect, to: self.view)
// do something with rect
}
感谢 Ken Thomases
我有一个 NSTextField,里面有一句话。我想为句子中的每个单词找到一个矩形(理想情况下)或位置以在这些位置(在 NSTextField 之外)做事。
使用 NSLayoutManager.boundingRectForGlyphRange
在 NSTextView/UITextView
我在 NSTextField 中查找给定单词位置的最佳方法是什么?
它需要一个 barely-documented 位魔术和另一个完全未记录的位。这是 Objective-C 代码。抱歉,Swift 中没有它。
NSRect textBounds = [textField.cell titleRectForBounds:textField.bounds];
NSTextContainer* textContainer = [[NSTextContainer alloc] init];
NSLayoutManager* layoutManager = [[NSLayoutManager alloc] init];
NSTextStorage* textStorage = [[NSTextStorage alloc] init];
[layoutManager addTextContainer:textContainer];
[textStorage addLayoutManager:layoutManager];
textContainer.lineFragmentPadding = 2;
layoutManager.typesetterBehavior = NSTypesetterBehavior_10_2_WithCompatibility;
textContainer.containerSize = textBounds.size;
[textStorage beginEditing];
textStorage.attributedString = textField.attributedStringValue;
[textStorage endEditing];
NSUInteger count;
NSRectArray rects = [layoutManager rectArrayForCharacterRange:matchRange
withinSelectedCharacterRange:matchRange
inTextContainer:textContainer
rectCount:&count];
for (NSUInteger i = 0; i < count; i++)
{
NSRect rect = NSOffsetRect(rects[i], textBounds.origin.x, textBounds.origin.y);
rect = [textField convertRect:rect toView:self];
// do something with rect
}
typesetterBehavior
被记录在案 here。 lineFragmentPadding
是根据经验确定的。
根据您打算对矩形执行的具体操作,您可能希望传递 { NSNotFound, 0 }
作为所选字符范围。
为了提高效率,您通常希望保留文本对象而不是每次都实例化它们。您只需每次将文本容器的 containerSize
和文本存储的 attributedString
设置为适当的值。
根据 Ken Thomases 的回答。我为 Swift 4.2
做了改编 guard let textFieldCell = textField.cell,
let textFieldCellBounds = textFieldCell.controlView?.bounds else{
return
}
let textBounds = textFieldCell.titleRect(forBounds: textFieldCellBounds)
let textContainer = NSTextContainer()
let layoutManager = NSLayoutManager()
let textStorage = NSTextStorage()
layoutManager.addTextContainer(textContainer)
textStorage.addLayoutManager(layoutManager)
layoutManager.typesetterBehavior = NSLayoutManager.TypesetterBehavior.behavior_10_2_WithCompatibility
textContainer.containerSize = textBounds.size
textStorage.beginEditing()
textStorage.setAttributedString(textFieldCell.attributedStringValue)
textStorage.endEditing()
let rangeCharacters = (textFieldCell.stringValue as NSString).range(of: "string")
var count = 0
let rects: NSRectArray = layoutManager.rectArray(forCharacterRange: rangeCharacters,
withinSelectedCharacterRange: rangeCharacters,
in: textContainer,
rectCount: &count)!
for i in 0...count {
var rect = NSOffsetRect(rects[i], textBounds.origin.x, textBounds.origin.y)
rect = textField.convert(rect, to: self.view)
// do something with rect
}
感谢 Ken Thomases