[英]Draw NSTableView Alternating Rows Like iTunes 11
我知道關於改變交替的行顏色還有其他問題。 這很容易,這不是我想要做的。
我想在基於視圖的NSTableView中繪制自定義交替顏色的行,這些行看起來像來自iTunes 11(行的頂部和底部的輕微邊框,如此屏幕截圖所示):
我知道我可以繼承NSTableRowView並在那里進行自定義繪圖。 但是,這不是一個可接受的答案,因為自定義行僅用於表中包含數據的行。 換句話說,如果表只有5行,那5行將使用我的自定義NSTableRowView類,但表中其余部分的剩余“行”(它們是空的)將使用標准的交替顏色。 在這種情況下,前5行將顯示擋板,其余的不顯示。 不好。
那么,我怎樣才能破解NSTableView為填充行和空行繪制這些樣式的交替行?
正如你所說的那樣,“輕微的邊框”實際上可以通過我們的一點點作弊輕松完成。 因為,如果仔細觀察,每個單元格的頂部比黑暗的交替行稍微淺一些藍色,並且每個單元格的底部是深灰色,你可以- (void)drawRow:(NSInteger)row clipRect:(NSRect)clipRect
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];
}
當在快速的小桌面視圖中完成時,它看起來像這樣:
但是如何處理tableview的頂部和底部? 畢竟,它們仍然是一個丑陋的白色,或默認的交替行顏色。 好吧,正如Apple所揭示的那樣(在一篇名為“基於視圖的NSTableView,基礎到高級”的討論中 ,你可以覆蓋-(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++;
}
}
完成所有操作后,我們會在剪輯視圖的頂部和底部獲得漂亮的小型假視圖單元格行,看起來有點像這樣:
完整的子類可以在這里找到。
您可以使用
- (void)setUsesAlternatingRowBackgroundColors:(BOOL)useAlternatingRowColors
with useAlternatingRowColors
YES指定背景的標准交替行顏色,NO指定純色。
我發現你可以在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)
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.