The next section uses the NSTextView subclass, which must be created in code. For reasons of its own, Xcode will not be allowed to instantiate an NSTextView at the tip without an enclosing NSScrollView instance.
This class allows you to determine only the internal height of the text - the width remains undefined, which allows you to increase the view with its closing view. I used this in NSStackView and it seems to work well. Trying to trick NSTextField so that it could wrap multi-line text, edit and maintain automatic layout was too messy.
Please note that we support the focus ring as I wanted my class to work as an Uber text box. Also note that we do not support the border. In my actual use, I create a composite view that wraps a custom text view. This kind of shell draws a border as needed.
@interface BPTextViewField : NSTextView // primitives @property (assign, nonatomic) CGFloat borderOffsetX; @property (assign, nonatomic) CGFloat borderOffsetY; @end @implementation BPTextViewField #pragma mark - #pragma mark Life cycle - (instancetype)initWithFrame:(NSRect)frameRect textContainer:(nullable NSTextContainer *)container { self = [super initWithFrame:frameRect textContainer:container]; if (self) { [self commonInit]; } return self; } - (nullable instancetype)initWithCoder:(NSCoder *)coder { self = [super initWithCoder:coder]; if (self) { [self commonInit]; } return self; } - (void)commonInit { _borderOffsetX = 1; _borderOffsetY = 3; self.usesFontPanel = NO; self.usesFindPanel = NO; } #pragma mark - #pragma mark Auto layout - (NSSize)intrinsicContentSize { NSTextContainer* textContainer = [self textContainer]; NSLayoutManager* layoutManager = [self layoutManager]; [layoutManager ensureLayoutForTextContainer: textContainer]; NSSize size = [layoutManager usedRectForTextContainer: textContainer].size; return NSMakeSize(NSViewNoIntrinsicMetric, size.height); } #pragma mark - #pragma mark Accessors - (void)setString:(NSString *)string { [super setString:string]; [self invalidateIntrinsicContentSize]; } #pragma mark - #pragma mark Text change notifications - (void)didChangeText { [super didChangeText]; [self invalidateIntrinsicContentSize]; } #pragma mark - #pragma mark Drawing - (void)drawRect:(NSRect)rect { [super drawRect:rect]; } #pragma mark - #pragma mark Focus ring - (void)drawFocusRingMask { if (self.editable) { NSRectFill(self.focusRingMaskBounds); } } - (NSRect)focusRingMaskBounds { NSRect r = [self bounds]; return NSMakeRect(r.origin.x - self.borderOffsetX, r.origin.y - self.borderOffsetY, r.size.width + self.borderOffsetX * 2, r.size.height + self.borderOffsetY * 2); } @end
source share