views:

23

answers:

1

I am using an NSTokenField as a way for users to enter tags. Everything works fine and it hooks up with CoreData managing the tags both when the user adds or deletes a tag.

I recently added logic so that the NSTokenField would resize vertically as the user adds tags and they break to the next line using Andrew Bowman's IFVerticallyExpandingTextField. Again this all works fine.

The issue is that when I have to initially populate the NSTokenField with tags, I need it to resize. I populate the field by calling:

[tagField setObjectValue: anArray];

Where anArray is a series of objects that represent a tag or a Token. This in turn calls the NSTokenField delegate method

tokenField:displayStringForRepresentedObject:

Which returns the string representation for the object passed in the previous array.

I need to resize the NSTokenField after all of the calls to displayStringForRepresentedObject. Does anyone have any ideas of a notification or a way of finding out that it's all done? Even a way of calling the resize in between each call to displayStringForRepresentedObject would probably work.

Thanks in advance.

A: 

You might try something similar to -setNeedsDisplay: and -displayIfNeeded ... i.e., -setNeedsSizeToFit: and -sizeToFitIfNeeded.

You'll just need a "needsSizeToFit" BOOL flag and the -setNeedsSizeToFit: and -sizeToFitIfNeeded methods.

After you set your tokens, call -setNeedsSizeToFit:YES. It in turn will set the instance's needsSizeToFit flag, then if the flag is YES, it will call [self performSelector:@selector(sizeToFitIfNeeded) withObject:nil afterDelay:0]. Your -sizeToFitIfNeeded method will check if your needsSizeToFit flag is YES, call [self sizeToFit], then set the needsSizeToFit flag to NO.

Update

Here's a complete class (JLNAutoSizingTokenField) that does basic autosizing as described above. The only augmentation was to call this in the afore-mentioned delegate method:

- (NSString *)tokenField:(NSTokenField *)aTokenField 
displayStringForRepresentedObject:(id)representedObject
{
    [(JLNAutoSizingTokenField *)aTokenField setNeedsSizeToFit:YES];
    return representedObject;
}
Joshua Nozzi
I started to do something similar to this but I ran into the issue of not knowing when all my tokens are set. That's the real issue I'm having. They are not set after I setObjectValue. They are only set after each displayStringForRepresentedObject is called.
skabob11
Wouldn't -displayStringForRepresentedObject: be called within the same trip through the runloop as your -setObjectValue: call? If so, then the -sizeToFitIfNeeded would be called in the next trip through the runloop, *after* all the calls to -displayStringForRepresentedObject:.
Joshua Nozzi
Worst case scenario: an unsavory-looking-but-functional call to -setNeedsSizeToFit: with each call to -displayStringForRepresentedObject:.
Joshua Nozzi
setObjectValue is called once and then NSTokenField calls displayString for each object in objectValue. I have to try calling the resize method in the diplayStringForRepresentedObject again because when I tried that before it was messing up the strings themselves. The token field didn't like me calling the resize method while it was doing what it needed to do.
skabob11
Really unsavory would be, and I haven't tried this yet, would be to call a method each time displayStringForRepresentedObject is called and figuring out if its about to display the last one. At that point call the resize method with a delay of 0.1 or something. Calling resize from the displayStringForRepresentedObject is weird because it returns a string. So I call the resize before it returns the string and then would ultimately end up with one string that wasn't accounted for.
skabob11
I'm not sure you're getting my point about the run loop and -performSelector:withObject:afterDelay: ...
Joshua Nozzi
But -textDidEndEditing is never called as the text is not actually edited. I will be able try things you've mentioned here later on today and will be able to actually say for sure whats working and whats not.
skabob11
I thought about it again and see what you mean now about utilizing the run loop. I'm going to try that later. Thanks.
skabob11
Tested it and it works fine. Here's a completed class: http://joshua.nozzi.name/source/jlnautosizingtokenfield/ Updated my answer to include this.
Joshua Nozzi
I just got it working as you posted the class. It worked perfectly. Thanks for the help.
skabob11