Scrolling NSTokenField -- Clips a little if resized quickly (see movie)
Scrolling NSTokenField -- Clips a little if resized quickly (see movie)
- Subject: Scrolling NSTokenField -- Clips a little if resized quickly (see movie)
- From: Jerry Krinock <email@hidden>
- Date: Sat, 13 Jun 2009 12:07:44 -0700
In the list archives I've seen where others have wanted an
NSTokenField in an NSScrollView, and have been stymied by the lack of
access to the layout mechanism in NSTokenField. So I worked around
this by adding tags one at a time, emulating the layout that
NSTokenField must be doing. It's tedious, but works and doesn't hack
into any Apple private methods. See code below.
There is one tiny problem. My scroll view autoresizes with its
superview RBSplitSubview. If I slowly drag the split bar so as to
decrease the split subview size until scrollers appear, all is fine.
But if drag it quickly, the token field shifts upward so that part of
its first row is clipped. A little Snapz Pro X movie is worth 10,000
words...
http://sheepsystems.com/engineering/Tokenz.mov (1.3 MB)
None of my code is running when this happens. You may notice that I
have TinkerTool'ed my account to show scrollers on both ends of the
scroll bar, but the same thing happens if I run on an un-tinkered Mac
account. I've got Mac OS X 10.5.7. Does anyone have a possible
explanation or workaround?
Thank you,
Jerry Krinock
**** This method may be put into an NSTokenField subclass or category.
**** Invoke it method after setting the object value (tokens array).
**** Declaration ****
/*!
@brief Sizes the receiver's height to fit its current tokens in
the current frame width, or the height of its enclosing scroll view,
if one exists, whiever is greater.
@details Sizing is based on an interrow spacing of 2.0 which was
determined empirically since NSTokenField, unlike NSTableView, does
not make its interrow spacing accessible, and also the fact that
the interrow spacing seems to be independent of font size.
This has been tested with the token field's font size set to
-[NSFont systemFontOfSize:11.0] and -[NSFont systemFontOfSize:
11.0].
The code may need to be tweaked if Apple ever changes the layout
algorithm of NSTokenField.
*/
- (void)sizeHeightToFit ;
**** Implementation ****
- (void)sizeHeightToFit {
NSArray* allTokens = [self objectValue] ;
NSInteger allTokensCount = [allTokens count] ;
CGFloat availableWidth = [self frame].size.width ;
NSInteger nRows = 1 ;
NSInteger startingToken = 0 ;
NSInteger nTokensInThisRow = 0 ;
NSInteger nTokensPlaced = 0 ;
CGFloat height = 0.0 ;
CGFloat totalHeightWithOneRow = 0.0 ;
CGFloat tokenHeight ;
CGFloat interrowSpace = 2.0 ; // Determined empirically
while (nTokensPlaced < allTokensCount) {
NSRange tokenRange = NSMakeRange(startingToken,
nTokensInThisRow + 1) ;
NSArray* currentRowTokens = [allTokens
subarrayWithRange:tokenRange] ;
[self setObjectValue:currentRowTokens] ;
[self sizeToFit] ;
if (totalHeightWithOneRow == 0.0) {
totalHeightWithOneRow = [self frame].size.height ;
tokenHeight = totalHeightWithOneRow - interrowSpace ;
// Initial height: one token, plus space above, plus
space below
height = (tokenHeight + 2 * interrowSpace) ;
}
CGFloat requiredWidth = [self frame].size.width ;
if (requiredWidth > availableWidth) {
nRows++ ;
if (nRows == 1) {
// This would only happen if the first token by
itself was too wide
// to fit in a row, which would be very rare
height += (tokenHeight + 2 * interrowSpace) ;
}
else {
height += (tokenHeight + interrowSpace) ;
}
startingToken = startingToken + nTokensInThisRow ;
nTokensInThisRow = 0 ;
}
else {
nTokensInThisRow++ ;
nTokensPlaced++ ;
}
}
[self setFrame:NSMakeRect(
[self frame].origin.x,
[self frame].origin.y,
availableWidth,
height
)] ;
// Restore all tokens
[self setObjectValue:allTokens] ;
}
_______________________________________________
Cocoa-dev mailing list (email@hidden)
Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com
Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden