我知道在改变交替的行颜色方面还有其他问题。这很容易,而不是我想做的事。
我想在基于视图的NSTableView中绘制自定义交替颜色的行,这些行看起来像来自iTunes 11(行的顶部和底部的轻微边框,如此屏幕截图所示):
我知道我可以继承NSTableRowView并在那里进行自定义绘图。但是,这不是一个可接受的答案,因为自定义行仅用于表中包含数据的行。换句话说,如果表只有5行,那5行将使用我的自定义NSTableRowView类,但表中其余部分的剩余“行”(它们是空的)将使用标准的交替颜色。在这种情况下,前5行将显示挡板,其余的不显示。不好。
那么,我怎样才能破解NSTableView为填充行和空行绘制这些样式的交替行?
答案 0 :(得分:15)
正如你所说的那样,“轻微的边框”实际上可以很容易地完成,我们会做一点作弊。因为,如果你仔细观察,每个单元格的顶部比黑暗的交替行稍微浅蓝色,并且每个单元格的底部是深灰色,你可以继承NSTableView,然后覆盖- (void)drawRow:(NSInteger)row clipRect:(NSRect)clipRect
:< / p>
- (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];
}
当在快速的小桌面视图中完成时,看起来像这样:
但是如何处理tableview的顶部和底部?毕竟,它们仍然是一个丑陋的白色,或默认的交替行颜色。好吧,正如苹果公司所揭示的那样(在一篇题为“{3}}”的谈话中,你可以覆盖-(void)drawBackgroundInClipRect:(NSRect)clipRect
并做一些数学运算来绘制tableview的背景,就像额外的行一样。快速实现看起来像这样:
-(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--;
}
}
}
但是,这会让桌面的底部留下同样丑陋的空白色!因此,我们还必须覆盖-(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++;
}
}
当完成所有操作后,我们会在剪辑视图的顶部和底部获得漂亮的小型假视图单元格行,看起来有点像这样:
答案 1 :(得分:1)
你可以使用
- (void)setUsesAlternatingRowBackgroundColors:(BOOL)useAlternatingRowColors
使用useAlternatingRowColors
YES指定背景的标准交替行颜色,NO指定纯色。
答案 2 :(得分:0)
我发现您可以在drawBackgroundInClipRect
中绘制顶部和底部 - 主要是在@ CodaFi解决方案的缺失else
子句中。
所以这是Swift中的一种方法,假设您可以访问backgroundColor
和alternateBackgroundColor
:
override func drawBackground(inClipRect clipRect: NSRect) {
// I didn't find leaving this out changed appearance at all unlike
// CodaFi stated.
super.drawBackground(inClipRect: clipRect)
guard usesAlternatingRowBackgroundColors else { return }
drawTopAlternatingBackground(inClipRect: clipRect)
drawBottomAlternatingBackground(inClipRect: clipRect)
}
fileprivate func drawTopAlternatingBackground(inClipRect clipRect: NSRect) {
guard clipRect.origin.y < 0 else { return }
let backgroundColor = self.backgroundColor
let alternateColor = self.alternateBackgroundColor
let rectHeight = rowHeight + intercellSpacing.height
let minY = NSMinY(clipRect)
var row = 0
while true {
if row % 2 == 0 {
backgroundColor.setFill()
} else {
alternateColor.setFill()
}
let rowRect = NSRect(
x: 0,
y: (rectHeight * CGFloat(row) - rectHeight),
width: NSMaxX(clipRect),
height: rectHeight)
NSRectFill(rowRect)
drawBezel(inRect: rowRect)
if rowRect.origin.y < minY { break }
row -= 1
}
}
fileprivate func drawBottomAlternatingBackground(inClipRect clipRect: NSRect) {
let backgroundColor = self.backgroundColor
let alternateColor = self.alternateBackgroundColor
let rectHeight = rowHeight + intercellSpacing.height
let maxY = NSMaxY(clipRect)
var row = rows(in: clipRect).location
while true {
if row % 2 == 1 {
backgroundColor.setFill()
} else {
alternateColor.setFill()
}
let rowRect = NSRect(
x: 0,
y: (rectHeight * CGFloat(row)),
width: NSMaxX(clipRect),
height: rectHeight)
NSRectFill(rowRect)
drawBezel(inRect: rowRect)
if rowRect.origin.y > maxY { break }
row += 1
}
}
func drawBezel(inRect rect: NSRect) {
let topLine = NSRect(x: 0, y: NSMaxY(rect) - 1, width: NSWidth(rect), height: 1)
NSColor(calibratedWhite: 0.912, alpha: 1).set()
NSRectFill(topLine)
let bottomLine = NSRect(x: 0, y: NSMinY(rect) , width: NSWidth(rect), height: 1)
NSColor(calibratedRed:0.961, green:0.970, blue:0.985, alpha:1).set()
NSRectFill(bottomLine)
}
如果您没有绘制NSTableRowView
子类:
override func drawRow(_ row: Int, clipRect: NSRect) {
let rowRect = rect(ofRow: row)
let color = row % 2 == 0 ? self.backgroundColor : self.alternateBackgroundColor
color.setFill()
NSRectFill(rowRect)
drawBezel(inRect: rowRect)
}