NSScrollView and NSTrackingArea woes
NSScrollView and NSTrackingArea woes
- Subject: NSScrollView and NSTrackingArea woes
- From: João Varela <email@hidden>
- Date: Wed, 15 Jul 2015 11:08:26 +0100
Hi,
I am implementing two custom classes, one of them is the document view inside an NSScrollView and the other is a subview of the document view. I need to create two NSTrackingArea’s to display the appropriate cursor when the mouse hovers over specific areas of the subviews. As instructed by Apple, I implemented an -updateTrackingAreas method to update the tracking areas when needed. Everything works as expected if the window and its views and subviews are resized or if the app is re-activated or the window becomes the key window again. Everything works well too when the user scrolls up or down to the end of the document view. The NSTrackingArea’s are updated correctly and the -updateTrackingAreas method is called in all these occasions.
However, none of this happens when the user only scrolls (up or down) a little and does not reach the top or bottom of the document view. In this case, not only the -updateTrackingAreas method of the subview is not called, but also the cursor is no longer updated properly, because the NSTrackingArea’s of the subviews have not updated correctly. It seems as though I am not the only one getting bitten by this problem. See here:
http://stuccy.com/questions/17731292/mouseovers-in-nscollectionviewnsscrollview <http://stuccy.com/questions/17731292/mouseovers-in-nscollectionviewnsscrollview>
I tried to circumvent this problem by detecting when the origin.y of the document view rect is not changing anymore within the NSScrollView (this is not easy on OS X because there is no notification to tell us when scrolling ended if you want to support OS X 10.8). For this purpose, I added a method in a NSScrollView subclass that does just that:
- (void)updateTrackingAreas
{
if (_y != self.documentVisibleRect.origin.y)
{
_y = self.documentVisibleRect.origin.y;
if (!_isScheduled)
{
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.0 * NSEC_PER_SEC)),
dispatch_get_main_queue(),
^{
if (_y != self.documentVisibleRect.origin.y)
{
[self updateTrackingAreas];
}
else
{
[_documentView updateTrackingAreas];
}
_isScheduled = NO;
});
_isScheduled = YES;
}
}
}
This method is called every time the user uses the scroll wheel as it is invoked inside the -scrollWheel method of the NSScrollView subclass. It works as expected and coalesces all the scroll wheel events into just one call. When the scrolling stops, indeed the [_documentView updateTrackingAreas] is called, which then invokes the subview’s -updateTrackingAreas method. This should do the trick, but it doesn’t.
Thus, before I try the solution given in the link above, which I find even more hacky than my own solution, is there something that I am missing? Why wouldn’t the NSTrackingArea’s update correctly when they do so if the window is resized or becomes key again or the user scrolls up or down to the end? What is the OS doing in these situations that I am not doing here?
I would appreciate any feedback,
J. Varela
_______________________________________________
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