
如何在Cocoa (OS X)中绘制此样式的文本?它似乎在几个苹果应用程序中使用,包括Mail (如上图)和Xcode侧边栏中的几个地方。我环顾四周,但没有找到任何建议如何重现这种特定风格的文本的资源。它看起来像一个嵌入的阴影,我的第一个猜测是尝试使用模糊半径设置为负值的NSShadow,但显然只允许正值。有什么想法吗?
发布于 2014-01-06 10:33:45
我有一些绘制浮雕单元格的代码(我相信最初写的是Jonathon Mah )。它可能做不到你想要的,但它会给你一个开始的地方:
@implementation DMEmbossedTextFieldCell
#pragma mark NSCell
- (void)drawInteriorWithFrame:(NSRect)cellFrame inView:(NSView *)controlView;
{
/* This method copies the three-layer method used by Safari's error page. That's accessible by forcing an
* error (e.g. visiting <foo://>) and opening the web inspector. */
// I tried to use NSBaselineOffsetAttributeName instead of shifting the frame, but that didn't seem to work
const NSRect onePixelUpFrame = NSOffsetRect(cellFrame, 0.0, [NSGraphicsContext currentContext].isFlipped ? -1.0 : 1.0);
const NSRange fullRange = NSMakeRange(0, self.attributedStringValue.length);
NSMutableAttributedString *scratchString = [self.attributedStringValue mutableCopy];
BOOL overDark = (self.backgroundStyle == NSBackgroundStyleDark);
CGFloat (^whenLight)(CGFloat) = ^(CGFloat b) { return overDark ? 1.0 - b : b; };
// Layer 1
[scratchString addAttribute:NSForegroundColorAttributeName value:[NSColor colorWithCalibratedWhite:whenLight(1.0) alpha:1.0] range:fullRange];
[scratchString drawInRect:cellFrame];
// Layer 2
BOOL useGradient = NO; // Safari 5.2 preview has switched to a lighter, solid color look for the detail text. Since we use the same class, use bold-ness to decide
if (self.attributedStringValue.length > 0) {
NSFont *font = [self.attributedStringValue attribute:NSFontAttributeName atIndex:0 effectiveRange:NULL];
if ([[NSFontManager sharedFontManager] traitsOfFont:font] & NSBoldFontMask)
useGradient = YES;
}
NSColor *solidShade = [NSColor colorWithCalibratedHue:200/360.0 saturation:0.03 brightness:whenLight(0.41) alpha:1.0];
[scratchString addAttribute:NSForegroundColorAttributeName value:solidShade range:fullRange];
[scratchString drawInRect:onePixelUpFrame];
// Layer 3 (Safari uses alpha of 0.25)
[scratchString addAttribute:NSForegroundColorAttributeName value:[NSColor colorWithCalibratedWhite:whenLight(1.0) alpha:0.25] range:fullRange];
[scratchString drawInRect:cellFrame];
}
@end发布于 2014-01-19 20:03:36
请不要选择这个作为答案,我只是为了好玩而实现了上面的建议,并把它放在这里,因为它可能会在未来对某些人有用!
https://github.com/danieljfarrell/InnerShadowTextFieldCell

根据indragie和wil-shipley的建议,这里是NSTextFieldCell的一个子类,它用内部阴影绘制文本。
头文件,
// InnerShadowTextFieldCell.h
#import <Cocoa/Cocoa.h>
@interface InnerShadowTextFieldCell : NSTextFieldCell
@property (strong) NSShadow *innerShadow;
@end现在是实现文件,
// InnerShadowTextFieldCell.m
#import "InnerShadowTextFieldCell.h"
// This class needs the NSString category -bezierWithFont: from,
// https://developer.apple.com/library/mac/samplecode/SpeedometerView/Listings/SpeedyCategories_m.html
@implementation InnerShadowTextFieldCell
- (void)drawInteriorWithFrame:(NSRect)cellFrame inView:(NSView *)controlView {
//// Shadow Declarations
if (_innerShadow == nil) {
/* Inner shadow has not been set, override here with default shadow.
You may or may not want this behaviour. */
_innerShadow = [[NSShadow alloc] init];
[_innerShadow setShadowColor: [NSColor darkGrayColor]];
[_innerShadow setShadowOffset: NSMakeSize(0.1, 0.1)];
/* Trying to find a default shadow radius which will look good for
a label of any size, let's get a rough estimate based on the
hypotenuse of the cell frame. */
[_innerShadow setShadowBlurRadius: 0.0075 * hypot(NSWidth(cellFrame), NSHeight(cellFrame)) ];
}
/* Because we are using the -bezierWithFont: we get a slightly
different path than had we used the superclass to drawn the
text path. This means that the background colour and text
colour looks odd if we use call the superclass's,
-drawInteriorWithFrame:inView: method let's do that
drawing here. Not making the call to super might cause
problems for general use (?) but for a simple label is seems
to work OK */
[self.backgroundColor setFill];
NSRectFill(cellFrame);
NSBezierPath *bezierPath = [self.title bezierWithFont:self.font];
[self.textColor setFill];
[bezierPath fill];
/* The following is inner shadow drawing method is taken from Paint Code */
////// Bezier Inner Shadow
NSShadow *shadow = _innerShadow;
NSRect bezierBorderRect = NSInsetRect([bezierPath bounds], -shadow.shadowBlurRadius, -shadow.shadowBlurRadius);
bezierBorderRect = NSOffsetRect(bezierBorderRect, -shadow.shadowOffset.width, shadow.shadowOffset.height);
bezierBorderRect = NSInsetRect(NSUnionRect(bezierBorderRect, [bezierPath bounds]), -1, -1);
NSBezierPath* bezierNegativePath = [NSBezierPath bezierPathWithRect: bezierBorderRect];
[bezierNegativePath appendBezierPath: bezierPath];
[bezierNegativePath setWindingRule: NSEvenOddWindingRule];
[NSGraphicsContext saveGraphicsState];
{
NSShadow* shadowWithOffset = [shadow copy];
CGFloat xOffset = shadowWithOffset.shadowOffset.width + round(bezierBorderRect.size.width);
CGFloat yOffset = shadowWithOffset.shadowOffset.height;
shadowWithOffset.shadowOffset = NSMakeSize(xOffset + copysign(0.0, xOffset), yOffset + copysign(0.1, yOffset));
[shadowWithOffset set];
[[NSColor grayColor] setFill];
[bezierPath addClip];
NSAffineTransform* transform = [NSAffineTransform transform];
[transform translateXBy: -round(bezierBorderRect.size.width) yBy: 0];
[[transform transformBezierPath: bezierNegativePath] fill];
}
[NSGraphicsContext restoreGraphicsState];
}
@end这可能会变得更健壮,但似乎只适用于绘制静态标签。
确保在Interface Builder中更改文本颜色和文本背景颜色属性,否则将看不到阴影。
发布于 2014-01-06 12:10:32
从你的屏幕截图看,这看起来像是用内阴影绘制的文本。因此,使用模糊半径为0的标准NSShadow方法将不起作用,因为它只在文本的下方/上方绘制阴影。
绘制带有内阴影的文本需要两个步骤。
1.获取文本的绘制路径
为了能够在文本字形内部绘制阴影,您需要从字符串创建bezier路径。苹果公司的示例代码SpeedometerView具有将方法-bezierWithFont:添加到NSString的a category。运行项目以查看如何使用此方法。
2.使用内部阴影填充路径
在bezier路径下绘制阴影很容易,但在其中绘制阴影并不容易。幸运的是,NSBezierPath+MCAdditions类别添加了-[NSBezierPath fillWithInnerShadow:]方法来简化这一过程。
https://stackoverflow.com/questions/20928743
复制相似问题