【Mac】NSTextField And AutoLayout: Autogrow height -> Programmatically

本文介绍了如何通过自定义 NSTextField 的子类来实现文本字段根据输入内容自动调整大小的功能。提供了三种不同的解决方案,包括使用 cellSizeForBounds 方法、监听文本编辑状态并更新内在尺寸以及在编辑过程中实时获取文本视图的布局尺寸。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

【solution1】

Hence, a custom subclass of NSTextField can override this method to return a better value, such as the one provided by the cell's cellSizeForBounds: method:

 

- (NSSize) intrinsicContentSize;
{
    const CGFloat magic = -4;

    NSSize rv;
    if ([[self cell] wraps] && self.frame.size.height > 1)
        rv = [[self cell] cellSizeForBounds:NSMakeRect(0, 0, self.bounds.size.width + magic, 20000)];
    else
        rv = [super intrinsicContentSize];
    return rv;
}

- (void) layout;
{
    [super layout];
    [self invalidateWordWrappedContentSizeIfNeeded];
}

- (void) setFrameSize:(NSSize)newSize;
{
    [super setFrameSize:newSize];
    [self invalidateWordWrappedContentSizeIfNeeded];
}

- (void) invalidateWordWrappedContentSizeIfNeeded;
{
    NSSize a = m_previousIntrinsicContentSize;
    NSSize b = self.intrinsicContentSize;
    if (!NSEqualSizes(a, b))
    {
        [self invalidateIntrinsicContentSize];
    }
    m_previousIntrinsicContentSize = b;
}

The reason I didn’t use cellSizeForBounds as you originally suggested was I couldn’t solve your problem – even when invalidating the intrinsic content size of the cell, cellSizeForBounds:continued to return the old size.

 

 

 

 

 

【solution2】

https://stackoverflow.com/questions/14107385/getting-a-nstextfield-to-grow-with-the-text-in-auto-layout

 

@interface TSTTextGrowth()
{
    BOOL _hasLastIntrinsicSize;
    BOOL _isEditing;
    NSSize _lastIntrinsicSize;
}

@end

@implementation TSTTextGrowth

- (void)textDidBeginEditing:(NSNotification *)notification
{
    [super textDidBeginEditing:notification];
    _isEditing = YES;
}

- (void)textDidEndEditing:(NSNotification *)notification
{
    [super textDidEndEditing:notification];
    _isEditing = NO;
}

- (void)textDidChange:(NSNotification *)notification
{
    [super textDidChange:notification];
    [self invalidateIntrinsicContentSize];
}

-(NSSize)intrinsicContentSize
{
    NSSize intrinsicSize = _lastIntrinsicSize;

    // Only update the size if we’re editing the text, or if we’ve not set it yet
    // If we try and update it while another text field is selected, it may shrink back down to only the size of one line (for some reason?)
    if(_isEditing || !_hasLastIntrinsicSize)
    {
        intrinsicSize = [super intrinsicContentSize];

        // If we’re being edited, get the shared NSTextView field editor, so we can get more info
        NSText *fieldEditor = [self.window fieldEditor:NO forObject:self];
        if([fieldEditor isKindOfClass:[NSTextView class]])
        {
            NSTextView *textView = (NSTextView *)fieldEditor;
            NSRect usedRect = [textView.textContainer.layoutManager usedRectForTextContainer:textView.textContainer];

            usedRect.size.height += 5.0; // magic number! (the field editor TextView is offset within the NSTextField. It’s easy to get the space above (it’s origin), but it’s difficult to get the default spacing for the bottom, as we may be changing the height

            intrinsicSize.height = usedRect.size.height;
        }

        _lastIntrinsicSize = intrinsicSize;
        _hasLastIntrinsicSize = YES;
    }

    return intrinsicSize;
}

@end

As a last note, I’ve never actually used auto layout myself – the demos look amazing, but whenever I actually try it myself, I can’t get it to work quite right and it makes things more complicated. However, in this case, I think it actually did save a bunch of work – without it, -intrinsicContentSize wouldn’t exist, and you’d possibly have to set the frame yourself, calculating the new origin as well as the new size (not too difficult, but just more code).

 

 

 

 

 

[solution3] height and width will change...

 

@implementation AutosizingTextField

- (void)textDidBeginEditing:(NSNotification *)notification
{
    [super textDidBeginEditing:notification];
    isEditing = YES;
}

- (void)textDidEndEditing:(NSNotification *)notification
{
    [super textDidEndEditing:notification];
    isEditing = NO;
}

- (void)textDidChange:(NSNotification *)notification
{
    [super textDidChange:notification];
    [self invalidateIntrinsicContentSize];
}

-(NSSize)intrinsicContentSize
{
    if(isEditing)
    {
        NSText *fieldEditor = [self.window fieldEditor:NO forObject:self];
        if(fieldEditor)
        {
            NSTextFieldCell *cellCopy = [self.cell copy];
            cellCopy.stringValue = fieldEditor.string;
            return [cellCopy cellSize];
        }
    }
    return [self.cell cellSize];
}
@end

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值