背景
下面的镜头是OS X Lion中的Mail.app。当源列表变得太长时,在源列表底部的按钮上方会出现一条漂亮的阴影线。滚动时,源列表会在该阴影线下移动。当您展开窗口以使源列表中的所有内容都适合而不滚动时,阴影线将消失。
问题:
如何使用Cocoa绘制这条阴影线?我知道NSShadow等等,但在我看来,这里发生的事情不仅仅是阴影。有一条线巧妙地淡化到点(就好像你在Photoshop中的每一端应用了渐变蒙版。)同样,阴影是椭圆并在接近线的末端时逐渐变细。所以它不只是常规的NSShadow,是吗? (它绝对不是图像,因为当您扩展源视图的宽度时,它可以很好地缩放。)
有关如何绘制此形状的任何提示将不胜感激。
对于那些坚持不懈的人来说,不,这并不违反NDA,因为Mail.app已经被Apple公开展示。
答案 0 :(得分:16)
150px × 10px
创建“图层A”图层
并使用 Gradient 填充:
#535e71
不透明度 33%
#535e71
不透明度: 0%
150px × 1px
创建“图层B”图层
并使用实心#535e71
不透明度填充: 50%
#ffffff
应用到#000000
到“C层”。
<强> MyView.h 强>:
#import <Cocoa/Cocoa.h>
@interface MyView : NSView {
@private
}
@end
<强> MyView.m 强>:
#import "MyView.h"
@implementation MyView
- (CGImageRef)maskForRect:(NSRect)dirtyRect {
NSSize size = [self bounds].size;
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
CGContextRef context = CGBitmapContextCreate(NULL, size.width, size.height, 8, 0, colorSpace, kCGImageAlphaPremultipliedLast);
CGContextClipToRect(context, *(CGRect*)&dirtyRect);
CGRect rect = CGRectMake(0.0, 0.0, size.width, size.height);
size_t num_locations = 3;
CGFloat locations[3] = { 0.0, 0.5, 1.0 };
CGFloat components[12] = {
1.0, 1.0, 1.0, 1.0, // Start color
0.0, 0.0, 0.0, 1.0, // Middle color
1.0, 1.0, 1.0, 1.0, // End color
};
CGGradientRef myGradient = CGGradientCreateWithColorComponents(colorSpace, components, locations, num_locations);
CGPoint myStartPoint = CGPointMake(CGRectGetMinX(rect), CGRectGetMinY(rect));
CGPoint myEndPoint = CGPointMake(CGRectGetMaxX(rect), CGRectGetMinY(rect));
CGContextDrawLinearGradient(context, myGradient, myStartPoint, myEndPoint, 0);
CGImageRef theImage = CGBitmapContextCreateImage(context);
CGImageRef theMask = CGImageMaskCreate(CGImageGetWidth(theImage), CGImageGetHeight(theImage), CGImageGetBitsPerComponent(theImage), CGImageGetBitsPerPixel(theImage), CGImageGetBytesPerRow(theImage), CGImageGetDataProvider(theImage), NULL, YES);
[(id)theMask autorelease];
CGColorSpaceRelease(colorSpace);
CGContextRelease(context);
return theMask;
}
- (void)drawRect:(NSRect)dirtyRect {
NSRect nsRect = [self bounds];
CGRect rect = *(CGRect*)&nsRect;
CGRect lineRect = CGRectMake(rect.origin.x, rect.origin.y, rect.size.width, (CGFloat)1.0);
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
CGContextRef context = (CGContextRef) [[NSGraphicsContext currentContext] graphicsPort];
CGContextClipToRect(context, *(CGRect*)&dirtyRect);
CGContextClipToMask(context, rect, [self maskForRect:dirtyRect]);
size_t num_locations = 2;
CGFloat locations[2] = { 0.0, 1.0 };
CGFloat components[8] = {
0.315, 0.371, 0.450, 0.3, // Bottom color
0.315, 0.371, 0.450, 0.0 // Top color
};
CGGradientRef myGradient = CGGradientCreateWithColorComponents(colorSpace, components, locations, num_locations);
CGPoint myStartPoint = CGPointMake(CGRectGetMinX(rect), CGRectGetMinY(rect));
CGPoint myEndPoint = CGPointMake(CGRectGetMinX(rect), CGRectGetMaxY(rect));
CGContextDrawLinearGradient(context, myGradient, myStartPoint, myEndPoint, 0);
CGContextSetRGBFillColor(context, 0.315, 0.371, 0.450, 0.5 );
CGContextFillRect(context, lineRect);
CGColorSpaceRelease(colorSpace);
}
@end
(我第一次使用纯粹的低级CoreGraphics,因此可能是次优的,可以进行改进。)
这是上面代码产生的实际屏幕截图:
图纸延伸到视图的尺寸。
(我以前有两种技术:“技术A”和“技术B” “技术B”提供了优异的结果,并且实施起来也更简单,所以我放弃了“技术A” 有些评论可能仍然提到“技术A”。只需忽略它们并享受功能完整的代码片段。)。
答案 1 :(得分:0)
水平拉伸的图像怎么样?
或者,如果您知道如何在Photoshop中制作一个,则可以通过编程方式应用相同的步骤。