Question

I want to put a text label over a scroll table but the label conflicts with the drawing of the scrolling. Here you can see a test where I've intentionally put the label half out of the table and scroll up in the table, which results in the part of the label overlay being dragged below until it exits the window.

scrolling up breaks label overlay

Also, when I go to the other end of the table and scroll down, sometimes the label seems to be redrawn and chunks of it go up along with the scroll:

scrolling down is bad too

scrolling down is bad too

It seems that the table is redrawing its contents and does not notify the rest of the view objects to redraw themselves in case they are overlaid. How do I solve this? In fact, this seems highly related to How to place an NSButton over an NSTableView which seems to have the same problem but with a button instead of a label.

Was it helpful?

Solution 2

Another alternative way to get proper redrawing is to open the xib root view in the Effects Inspector, and mark it to use the Core Animation Layer. This avoids requiring to create a custom class with the redrawing hook.

OTHER TIPS

Dont do that because you will lose a lot of performance and increase energy use.

Try the NSScrollView method - (void)addFloatingSubview:(NSView *)view forAxis:(NSEventGestureAxis)axis

That's because the scroll view is set to copy its contents when scrolling and only redraw the newly-uncovered part as a performance optimization. To turn that off, use

myScrollView.contentView.copiesOnScroll = NO;

though that will make scrolling use more CPU (you can also do this in the XIB, look for a 'copies on scroll' checkbox).

Probably a better approach would be to switch the scroll view and the button to be layer-backed:

myTableView.enclosingScrollView.wantsLayer = YES;
myTextView.wantsLayer = YES;

(Again, you can set this in the 'Layers' inspector of the XIB file, where you can click a checkbox next to each view to give it a layer) Now, the scroll view will only copy stuff from its own layer (which no longer includes your text view). Also, now all the compositing of the text view will be done using in the graphics card. However, if you put text on a transparent background in its own layer, you lose sub-pixel anti-aliasing. But if it's any other kind of view (or there's actually a solid background behind your text) this will look fine.

Yes, it seems that NSTableView caches the drawing of the hole table so that the scroll view doesn't have to refresh it for every pixel. However, that's exactly what is needed. Fortunately it can be done, I managed to subclass the NSScrollView in the following way to add a property and a hook to reflectScrolledClipView::

@interface EHScrollView : NSScrollView

@property (nonatomic, weak) NSView *refreshView;

@end

The implementation would be:

#import "EHScrollView.h"

@implementation EHScrollView

- (void)reflectScrolledClipView:(NSClipView *)aClipView
{
    [super reflectScrolledClipView:aClipView];
    [self.refreshView setNeedsDisplay:YES];
}

@end

The only thing needed then is to modify the xib for the user interface. Where the table is embedded in a scroll view, select the scroll view and modify it to inherit the custom class EHScrollView. Then, in the view controller initialisation, use outlets to both the scroll view and the table view to link the latter to the former through the refreshView property.

Now, every single scroll will automatically call setNeedsDisplay: on refreshView, which means that both the table and whatever is overlaid on top will be redrawn. Of course this is more performance intensive than a non refreshing table, so use only where it makes sense.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top