问题
Can't find any clue how to manage this.
By default, NSTextView selection highlights the whole size of its text container. It ignores line spacing, head or tail indents etc. But in Pages app selection doesn't highlight those ancillary parts, it highlight characters ONLY. And it highlights all the height of the line even if text container's height is smaller (paragraph spacing before and after).
I want to implement that behavior but can't understand where to begin. I've searched here, I've searched Apple docs, I've tried sample projects. Nothing.
Maybe someone can guide me in the right direction? Thanks!
回答1:
I found that hamstergene's answer isn't correct. In fact, NSTextView highlights its text container lines all over their bounds.
So, if you use paragraph's head indents then a leading the text empty space will be highlighted. And if you select EOL character then the tail of the text container will be highlighted.
My solution was to nullify head and tail indents of the paragraph style (I cache them in the private variable and put them back when my text storage is accessed for printing) and simply adjust frame of the text container line via overrided lineFragmentRectForProposedRect: atIndex: writingDirection: remainingRect method of my NSTextContainer subclass.
But then I found much proper way. Just override func fillBackgroundRectArray(_ rectArray: UnsafePointer<NSRect>, count rectCount: Int, forCharacterRange charRange: NSRange, color: NSColor)
of the NSLayoutManager, calculate your rects and call super with those rects. And if you calculated selection rectangles properly, you'll get the exact selection behavior like in Apple Pages or MS Word.
Simple and easy!
回答2:
We can only speculate what closed-source Pages use, but I doubt it is using NSTextView
— as a word processor it has to be using much more advanced custom solution.
Start from Cocoa Text Architecture Guide, you are primarily interested in NSLayoutManager
class (which is accompanied by NSTextContainer
and NSTextStorage
).
NSTextView
probably implements its selection via temporary attributes (-[NSLayoutManager addTemporaryAttribute:value:forCharacterRange:]
). If you subclass NSTextView
and intercept every selection changing event, you should be able to detect and remove temporary attribute(s) responsible for displaying selection from newline characters without interfering with text view's logical selection range.
If by some reason the above suggestion doesn't work, it is always possible to reimplement NSTextView
from scratch, using NSLayoutManager
to handle all layout and drawing. NSLayoutManager
handles all unicode/bidi quirks, giving out precise pixel coordinates of glyph runs and individual glyphs, as well as methods to draw them. The temporary attributes may be inadequate to implement different selection height; in that case you should be able to draw selection yourself (on the background under text glyphs). That is sure gonna be a lot of work for such a little UI detail, though.
来源:https://stackoverflow.com/questions/24407203/nstextview-selection-highlights-all-characters-even-paragraph-indents