PXSourceList
PXSourceList copied to clipboard
Custom background redraws oddly during show/hide
I've added the below method to PXSourceList.m to customize the background. When clicking Show/Hide on a parent row, the background has some redraw issues while collapsing or expanding. Before and after the Show/Hide operation the view is rendered fine, the problem just happens during the operation's animation.
- (void)drawBackgroundInClipRect:(NSRect)dirtyRect {
// Added this to customize outline view background
//// Color Declarations
NSColor* lightColor = [NSColor colorWithCalibratedRed: 0.701 green: 0.784 blue: 0.811 alpha: 1];
NSColor* transWhite = [NSColor colorWithCalibratedRed: 1 green: 1 blue: 1 alpha: 0.571];
NSColor* dkGray = [NSColor colorWithCalibratedRed: 0.4 green: 0.4 blue: 0.4 alpha: 1];
//// Gradient Declarations
NSGradient* transWhiteGradient = [[NSGradient alloc] initWithColorsAndLocations:
transWhite, 0.01,
[NSColor colorWithCalibratedRed: 0.799 green: 0.913 blue: 0.95 alpha: 0.785], 0.05,
lightColor, 0.37, nil];
//// Shadow Declarations
NSShadow* shadow = [[NSShadow alloc] init];
[shadow setShadowColor: dkGray];
[shadow setShadowOffset: NSMakeSize(0.1, -3.1)];
[shadow setShadowBlurRadius: 5.5];
//// Frames
//NSRect dirtyRect = NSMakeRect(0, 0, 214, 727);
//// baseRect Drawing
NSBezierPath* baseRectPath = [NSBezierPath bezierPathWithRect: NSMakeRect(NSMinX(dirtyRect), NSMinY(dirtyRect), NSWidth(dirtyRect), NSHeight(dirtyRect))];
[lightColor setFill];
[baseRectPath fill];
////// baseRect Inner Shadow
NSRect baseRectBorderRect = NSInsetRect([baseRectPath bounds], -shadow.shadowBlurRadius, -shadow.shadowBlurRadius);
baseRectBorderRect = NSOffsetRect(baseRectBorderRect, -shadow.shadowOffset.width, shadow.shadowOffset.height);
baseRectBorderRect = NSInsetRect(NSUnionRect(baseRectBorderRect, [baseRectPath bounds]), -1, -1);
NSBezierPath* baseRectNegativePath = [NSBezierPath bezierPathWithRect: baseRectBorderRect];
[baseRectNegativePath appendBezierPath: baseRectPath];
[baseRectNegativePath setWindingRule: NSEvenOddWindingRule];
[NSGraphicsContext saveGraphicsState];
{
NSShadow* shadowWithOffset = [shadow copy];
CGFloat xOffset = shadowWithOffset.shadowOffset.width + round(baseRectBorderRect.size.width);
CGFloat yOffset = shadowWithOffset.shadowOffset.height;
shadowWithOffset.shadowOffset = NSMakeSize(xOffset + copysign(0.1, xOffset), yOffset + copysign(0.1, yOffset));
[shadowWithOffset set];
[[NSColor grayColor] setFill];
[baseRectPath addClip];
NSAffineTransform* transform = [NSAffineTransform transform];
[transform translateXBy: -round(baseRectBorderRect.size.width) yBy: 0];
[[transform transformBezierPath: baseRectNegativePath] fill];
}
[NSGraphicsContext restoreGraphicsState];
[dkGray setStroke];
[baseRectPath setLineWidth: 1];
[baseRectPath stroke];
//// topRect Drawing
NSBezierPath* topRectPath = [NSBezierPath bezierPathWithRect: NSMakeRect(NSMinX(dirtyRect), NSMinY(dirtyRect) - 1, NSWidth(dirtyRect), NSHeight(dirtyRect) + 2)];
[transWhiteGradient drawInBezierPath: topRectPath angle: 90];
}
Do you have a sample project or video showing what happens?
Just used the attached class in place of the existing one in the example project. Note the drawBackgroundInClipRect method in the Drawing section, used to customize the background. I realize this isn't part of your release class, but I think it's important to get working correctly as people do more advanced things with their UIs.
Michael A. LaMorte Mac Developer Minder Softworks
On Oct 25, 2013, at 7:05 AM, Alex Rozanski [email protected] wrote:
Do you have a sample project or video showing what happens?
— Reply to this email directly or view it on GitHub.
It looks like the issue here is that the area you're drawing into is based on the dirtyRect
parameter that is passed in. The drawing issues are occurring because this method is often called to redraw small sections of the background (which are passed in as the dirtyRect
), which you're drawing into as if you were drawing the background of the entire view.
If you instead always redraw the entire background in this method then you don't get (most of) these drawing issues (as a quick test I just set dirtyRect
to self.enclosingScrollView.bounds
in the first line of the method). It's less efficient, but since you're working with gradients and shadows it would be tricky to do this more efficiently when only redrawing small areas.
For some reason, there is still a small flash of incorrect drawing when expanding and collapsing a section which I couldn't quite figure out. Let me know if you make progress with that.