0

我想实现一个NSTokenField跨越多行的。例如:

多行 NSTokenField

我在网上找到了一些多行的示例代码NSTokenField

IBOutlet NSTokenField *tokenField;

- (void)awakeFromNib
{
    [[tokenField cell] setWraps:YES];
}

让我的班级代表NSTokenField并实现以下方法

- (void)controlTextDidChange:(NSNotification *)obj {    
    NSRect oldTokenFieldFrame = [tokenField frame];
    NSRect tokenFieldBounds = [tokenField bounds];

    float height = oldTokenFieldFrame.size.height;
    tokenFieldBounds.size.height = CGFLOAT_MAX;
    NSSize cellSize = [[tokenField cell] cellSizeForBounds:tokenFieldBounds];

    float y = oldTokenFieldFrame.origin.y + height - cellSize.height;

    [tokenField setFrame:NSMakeRect(oldTokenFieldFrame.origin.x,
                                          y,
                                          oldTokenFieldFrame.size.width,
                                          cellSize.height)];
}

但是这段代码不能正常工作。

你能帮我解决这个问题吗?

先感谢您。

4

1 回答 1

0

对于所有正在寻找工作代码答案的人,我已经研究了@Willeke 的提示。NSTokenField因为这个解决方案在初始化一个with data in时没有考虑初始大小awakeFromNib,所以我将这个建议与这篇文章中的另一个解决方案结合起来。开始了:

#import "MyExpandingTokenField.h"

@interface MyExpandingTokenField()

@property Boolean isEditing;
@property Boolean hasLastIntrinsicSize;
@property NSSize lastIntrinsicSize;

@end

@implementation MyExpandingTokenField

#pragma mark Initializers and setup

- (id)init {
    if (self = [super init]) {
        [self commonSetupProcedure];
    }
    return self;
}

- (id)initWithCoder:(NSCoder *)coder {
    if (self = [super initWithCoder:coder]) {
        [self commonSetupProcedure];
    }
    return self;
}

- (void)commonSetupProcedure {
    [self setDelegate:self];
}

- (void)awakeFromNib {
    [self populateWithTestDataAndRefresh];
}

- (void)populateWithTestDataAndRefresh {
    // For testing initial size
    [self setObjectValue:@[@"asd", @"asfhgfgd", @"asd", @"asasasd", @"aasdsd", @"aAASsd", @"asd", @"asdaS"]];
}

#pragma mark MyExpandingTokenField methods

- (NSSize)initialIntrinsicContentSize {
    if (!self.cell.wraps) {
        return [super intrinsicContentSize];
    }
    NSRect frame = self.frame;
    frame.size.height = CGFLOAT_MAX;
    CGFloat height = [self.cell cellSizeForBounds: frame].height;
    return NSMakeSize(frame.size.width, height);
}

#pragma mark NSView overrides

- (NSSize)intrinsicContentSize {
    // This is where the real magic happens
    // https://stackoverflow.com/questions/14107385/getting-a-nstextfield-to-grow-with-the-text-in-auto-layout
    // https://stackoverflow.com/questions/17147366/auto-resizing-nstokenfield-with-constraint-based-layout/
    if (!self.hasLastIntrinsicSize) {
        self.lastIntrinsicSize = [self initialIntrinsicContentSize];
        self.hasLastIntrinsicSize = YES;
    }
    NSSize intrinsicSize = self.lastIntrinsicSize;
    if(self.isEditing) {
        intrinsicSize = [super intrinsicContentSize];
        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 += 6.0; // magic number!
            intrinsicSize.height = usedRect.size.height;
        }
        self.lastIntrinsicSize = intrinsicSize;
        self.hasLastIntrinsicSize = YES;
    }
    return intrinsicSize;
}

#pragma mark NSTexTFielDelegate implementation

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

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

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

@end
于 2022-02-24T10:53:51.957 回答