让 NSTextField 与自动布局中的文本一起增长? [英] getting a NSTextField to grow with the text in auto layout?

查看:33
本文介绍了让 NSTextField 与自动布局中的文本一起增长?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

一旦用户输入足够的文本以溢出控件的宽度(如询问这篇文章)

I'm trying to get my NSTextField to have its height grow (much like in iChat or Adium) once the user types enough text to overflow the width of the control (as asked on this post)

我已经暗示了已接受的答案,但我似乎无法让它发挥作用.我已在 http://scottyob.com/pub/autoGrowingExample.zip

I've implimented the accepted answer yet I can't seem to get it to work. I have uploaded my attempt at http://scottyob.com/pub/autoGrowingExample.zip

理想情况下,当文本增长时,包含窗口应该随之增长,但我在这里尝试了一些小步骤.

Ideally, when the text grows, the containing window should grow with it, but I'm trying baby steps here.

推荐答案

解决了!(灵感来自 https://github.com/jerrykrinock/CategoriesObjC/blob/master/NS(Attributed)String%2BGeometrics/NS(Attributed)String%2BGeometrics.m )

Solved it! (Inspired by https://github.com/jerrykrinock/CategoriesObjC/blob/master/NS(Attributed)String%2BGeometrics/NS(Attributed)String%2BGeometrics.m )

阅读 Apple 文档 通常很有帮助.Apple 设计了所有这些文本布局的东西,足以处理各种 复杂的边缘情况,有时非常有用,有时则不然.

Reading the Apple Documentation is usually helpful. Apple has engineered all this text layout stuff to be powerful enough to handle all sorts of complicated edge cases which is sometimes extremely helpful, and sometimes not.

首先,我将文本字段设置为在断字时换行,因此我们实际上得到了多行.(您的示例代码甚至有一个 if 语句,因此在关闭包装时它什么也没做).

Firstly, I set the text field to wrap lines on word break, so we actually get multiple lines. (Your example code even had an if statement so it did nothing at all when wrapping was turned off).

这个技巧是要注意,当文本被编辑时,它是由字段编辑器"打印的——一个重量级的 NSTextView 对象,由 NSWindow,它被任何 NSTextField 重用,当前是第一响应者"(已选择).NSTextView 有一个 NSTextContainer(文本所在的矩形),它有一个 NSLayoutManager 来布局文本.我们可以询问布局管理器它想要使用多少空间,以获得我们文本字段的新高度.

The trick to this one was to note that when text is being edited, it’s printed by a ‘field editor’ – a heavy weight NSTextView object, owned by an NSWindow, that’s reused by whatever NSTextField is currently the ‘first responder’ (selected). The NSTextView has a single NSTextContainer (rectangle where text goes), which has a NSLayoutManager to layout the text. We can ask the layout manager how much space it wants to use up, to get the new height of our text field.

另一个技巧是覆盖 NSText 委托方法 - (void)textDidChange:(NSNotification *)notification 以在文本更改时使内在内容大小无效(所以当你按回车键提交更改时,它不只是等待更新).

The other trick was to override the NSText delegate method - (void)textDidChange:(NSNotification *)notification to invalidate the intrinsic content size when the text is changed (so it doesn’t just wait to update when you commit changed by pressing return).

我没有像您最初建议的那样使用 cellSizeForBounds 的原因是我无法解决您的问题 - 即使使单元格的内在内容大小无效,cellSizeForBounds: 继续返回旧尺寸.

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.

GitHub 上查找示例项目.

Find the example project on GitHub.

@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

最后要注意的是,我自己从未真正使用过自动布局——演示看起来很棒,但每当我自己实际尝试时,我都无法让它正常工作,而且它使事情变得更加复杂.但是,在这种情况下,我认为它实际上确实节省了大量工作——没有它,-intrinsicContentSize 将不存在,您可能必须自己设置框架,计算新的原点以及新的大小(不是太难,只是代码更多).

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).

这篇关于让 NSTextField 与自动布局中的文本一起增长?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆