Friday, December 4, 2009

NSScrollView - problems

I have been having a strange problem scrolling in the TimeLine view. The issue is down to my understanding of coordinate spaces under "normal" (not flipped) circumstances in cocoa. The coordinate space is much as I expect - the bottom left corner is (0, 0). However when you come to NSScrollView things are a little strange. If the position of the content view also starts from the bottom left corner. This is 100% logical. What I did not count on was the effect when the content view is smaller than the NSScrollView. So, of your list, is smaller than the NSScrollView you can easily have this situation. What happens is that the bottom of the content view is placed as (0, 0) within the NSScrollView.The problem can be seen quite clearly if I expanded my evolving TimeLine so that the NSScrollView is larger than the content area. It looks as follows:

It took me a while to figure out the fix. MBTableView dealt with the problem forcing all the views to be flipped - so that (0, 0) is the top-left so it did not provide any kind of example. To get an example I downloaded the source code to CocoaTron. CocoaTron is an open source implementation of the cocoa frameworks. It is a cool project (don't let the web-site fool you it is actively developed) and the source code is there for you. You can find it here.

I pulled the CocoaTron source and had a look at their implementation of NSTableView. The solution is to grow the content view so that it is never smaller. Each time you resize the NSScrollView the NSTableView recalculates and repositions its self.

The solution:Add an override to resizeWithOldSuperviewSize that makes the content at least the size of it's superview. My resizeWithOldSuperviewSize would up looking like this:

-(void)resizeWithOldSuperviewSize:(NSSize)oldSize {

[super resizeWithOldSuperviewSize:oldSize];

[self reloadData];

}


My reloadData has also changed:

- (void)reloadData

{

.... stuff

NSRect contentRect = NSMakeRect(0, 0, _numberOfColumns * _columnWidth, _numberOfRows *_rowHeight);

contentRect.size.height = MAX(contentRect.size.height, [[self superview] bounds].size.height);

[contentView setFrameSize:contentRect.size];

.... stuff

}



No comments: