我知道在SO上还有其他有关更改交替行颜色的问题。这很简单,这不是我想要做的。
我想在基于 View 的NSTableView中绘制自定义的交替显示的行,这些行看起来像来自iTunes 11的行(该行的顶部和底部为浅边框,如此屏幕快照所示):
笔记:
我知道我可以继承NSTableRowView并在那里做我的自定义绘图。但是,这不是可接受的答案,因为自定义行将仅用于表中具有数据的行。换句话说,如果表只有5行,则这5行将使用我的自定义NSTableRowView类,但表其余部分(为空)中的其余“行”将使用标准交替色。在这种情况下,前5行将显示挡板,而其余5行将不显示。不好。
因此,我该如何破解NSTableView来为填充行和空行绘制这些样式交替的行?
最佳答案
就像您所说的那样,“轻微边框”实际上可以很容易地完成,只要我们稍加作弊即可。因为,如果仔细观察,每个单元格的顶部是比黑色交替行略浅的蓝色,而每个单元格的底部是暗灰色,则可以子类化NSTableView,然后重写- (void)drawRow:(NSInteger)row clipRect:(NSRect)clipRect
:
- (void)drawRow:(NSInteger)row clipRect:(NSRect)clipRect
{
//Use the drawing code from http://stackoverflow.com/a/5101923/945847, but change the colors to
//look like iTunes's alternating rows.
NSRect cellBounds = [self rectOfRow:row];
NSColor *color = (row % 2) ? [NSColor colorWithCalibratedWhite:0.975 alpha:1.000] : [NSColor colorWithCalibratedRed:0.932 green:0.946 blue:0.960 alpha:1.000];
[color setFill];
NSRectFill(cellBounds);
/* Slightly dark gray color */
[[NSColor colorWithCalibratedWhite:0.912 alpha:1.000] set];
/* Get the current graphics context */
CGContextRef currentContext = [[NSGraphicsContext currentContext]graphicsPort];
/*Draw a one pixel line of the slightly lighter blue color */
CGContextSetLineWidth(currentContext,1.0f);
/* Start the line at the top of our cell*/
CGContextMoveToPoint(currentContext,0.0f, NSMaxY(cellBounds));
/* End the line at the edge of our tableview, for multi-columns, this will actually be overkill*/
CGContextAddLineToPoint(currentContext,NSMaxX(cellBounds), NSMaxY(cellBounds));
/* Use the context's current color to draw the line */
CGContextStrokePath(currentContext);
/* Slightly lighter blue color */
[[NSColor colorWithCalibratedRed:0.961 green:0.970 blue:0.985 alpha:1.000] set];
CGContextSetLineWidth(currentContext,1.0f);
CGContextMoveToPoint(currentContext,0.0f,1.0f);
CGContextAddLineToPoint(currentContext,NSMaxX(self.bounds), 1.0f);
CGContextStrokePath(currentContext);
[super drawRow:row clipRect:clipRect];
}
在快速的小表格 View 中完成后,结果如下所示:
但是,如何处理tableview的顶部和底部?毕竟,它们仍然是丑陋的白色或默认的交替行颜色。好吧,正如Apple透露的那样(在一个有趣的View Based NSTableView, Basic To Advanced演讲中),您可以覆盖
-(void)drawBackgroundInClipRect:(NSRect)clipRect
并做一些数学运算以像额外的行一样绘制表格 View 的背景。快速实现如下所示:-(void)drawBackgroundInClipRect:(NSRect)clipRect
{
// The super class implementation obviously does something more
// than just drawing the striped background, because
// if you leave this out it looks funny
[super drawBackgroundInClipRect:clipRect];
CGFloat yStart = 0;
NSInteger rowIndex = -1;
if (clipRect.origin.y < 0) {
while (yStart > NSMinY(clipRect)) {
CGFloat yRowTop = yStart - self.rowHeight;
NSRect rowFrame = NSMakeRect(0, yRowTop, clipRect.size.width, self.rowHeight);
NSUInteger colorIndex = rowIndex % self.colors.count;
NSColor *color = [self.colors objectAtIndex:colorIndex];
[color set];
NSRectFill(rowFrame);
/* Slightly dark gray color */
[[NSColor colorWithCalibratedWhite:0.912 alpha:1.000] set];
/* Get the current graphics context */
CGContextRef currentContext = [[NSGraphicsContext currentContext]graphicsPort];
/*Draw a one pixel line of the slightly lighter blue color */
CGContextSetLineWidth(currentContext,1.0f);
/* Start the line at the top of our cell*/
CGContextMoveToPoint(currentContext,0.0f, yRowTop + self.rowHeight - 1);
/* End the line at the edge of our tableview, for multi-columns, this will actually be overkill*/
CGContextAddLineToPoint(currentContext,NSMaxX(clipRect), yRowTop + self.rowHeight - 1);
/* Use the context's current color to draw the line */
CGContextStrokePath(currentContext);
/* Slightly lighter blue color */
[[NSColor colorWithCalibratedRed:0.961 green:0.970 blue:0.985 alpha:1.000] set];
CGContextSetLineWidth(currentContext,1.0f);
CGContextMoveToPoint(currentContext,0.0f,yRowTop);
CGContextAddLineToPoint(currentContext,NSMaxX(clipRect), yRowTop);
CGContextStrokePath(currentContext);
yStart -= self.rowHeight;
rowIndex--;
}
}
}
但是,这却使表格 View 的底部变成了同样丑陋的空白白色!因此,我们还必须重写
-(void)drawGridInClipRect:(NSRect)clipRect
。另一个快速实现看起来像这样:-(void)drawGridInClipRect:(NSRect)clipRect {
[super drawGridInClipRect:clipRect];
NSUInteger numberOfRows = self.numberOfRows;
CGFloat yStart = 0;
if (numberOfRows > 0) {
yStart = NSMaxY([self rectOfRow:numberOfRows - 1]);
}
NSInteger rowIndex = numberOfRows + 1;
while (yStart < NSMaxY(clipRect)) {
CGFloat yRowTop = yStart - self.rowHeight;
NSRect rowFrame = NSMakeRect(0, yRowTop, clipRect.size.width, self.rowHeight);
NSUInteger colorIndex = rowIndex % self.colors.count;
NSColor *color = [self.colors objectAtIndex:colorIndex];
[color set];
NSRectFill(rowFrame);
/* Slightly dark gray color */
[[NSColor colorWithCalibratedWhite:0.912 alpha:1.000] set];
/* Get the current graphics context */
CGContextRef currentContext = [[NSGraphicsContext currentContext]graphicsPort];
/*Draw a one pixel line of the slightly lighter blue color */
CGContextSetLineWidth(currentContext,1.0f);
/* Start the line at the top of our cell*/
CGContextMoveToPoint(currentContext,0.0f, yRowTop - self.rowHeight);
/* End the line at the edge of our tableview, for multi-columns, this will actually be overkill*/
CGContextAddLineToPoint(currentContext,NSMaxX(clipRect), yRowTop - self.rowHeight);
/* Use the context's current color to draw the line */
CGContextStrokePath(currentContext);
/* Slightly lighter blue color */
[[NSColor colorWithCalibratedRed:0.961 green:0.970 blue:0.985 alpha:1.000] set];
CGContextSetLineWidth(currentContext,1.0f);
CGContextMoveToPoint(currentContext,0.0f,yRowTop);
CGContextAddLineToPoint(currentContext,NSMaxX(self.bounds), yRowTop);
CGContextStrokePath(currentContext);
yStart += self.rowHeight;
rowIndex++;
}
}
说完这些后,我们在clipview的顶部和底部就会得到一些漂亮的假tableview单元格行,看起来像这样:
完整的子类可以在here中找到。
关于objective-c - 绘制类似iTunes 11的NSTableView交替行,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/14178370/