更改NSTableView备用行颜色

问题描述 投票:17回答:8

我正在使用Interface Builder中的“Alternating Rows”选项在NSTableView上获取交替的行颜色。有没有办法改变交替行的颜色?

objective-c cocoa macos interface-builder nstableview
8个回答
7
投票

如果你想使用一种未记录的方式,请制作一个NSColor类别并覆盖_blueAlternatingRowColor,如下所示:

@implementation NSColor (ColorChangingFun)

+(NSColor*)_blueAlternatingRowColor
{
    return [NSColor redColor];
}

@end

或者要更改两种颜色,请覆盖controlAlternatingRowBackgroundColors以返回您想要交替的颜色数组。

@implementation NSColor (ColorChangingFun)

+(NSArray*)controlAlternatingRowBackgroundColors
{
    return [NSArray arrayWithObjects:[NSColor redColor], [NSColor greenColor], nil];
}

@end

7
投票

找到了更好的方法来做here。该方法会覆盖NSTableView子类中的highlightSelectionInClipRect:方法,因此您可以使用所需的任何颜色来替换交替行。它不像使用NSColor类别那样hackish,它只影响你选择的表视图。


4
投票

我将NSTableView子类化并实现了drawRow:clipRect:就像这样......

- (void)drawRow:(NSInteger)row clipRect:(NSRect)clipRect
{
    NSColor *color = (row % 2) ? [NSColor redColor] : [NSColor whiteColor];
    [color setFill];
    NSRectFill([self rectOfRow:row]);
    [super drawRow:row clipRect:clipRect];
}

它似乎有效,但它很简单,我想知道我是否遗漏了一些东西。


3
投票

我想要一个像常规NSTableView一样工作的解决方案,包括支持弹性滚动等等,所以我创建了一个NSTableView子类,它有一个名为NSColor*alternateBackgroundColor属性,然后像这样覆盖-drawBackgroundColorInClipRect:方法:

- (void) drawBackgroundInClipRect:(NSRect)clipRect {
    if([self alternateBackgroundColor] == nil) {
        // If we didn't set the alternate colour, fall back to the default behaviour
        [super drawBackgroundInClipRect:clipRect];
    } else {
        // Fill in the background colour
        [[self backgroundColor] set];
        NSRectFill(clipRect);

        // Check if we should be drawing alternating coloured rows
        if([self alternateBackgroundColor] && [self usesAlternatingRowBackgroundColors]) {
            // Set the alternating background colour
            [[self alternateBackgroundColor] set];

            // Go through all of the intersected rows and draw their rects
            NSRect checkRect = [self bounds];
            checkRect.origin.y = clipRect.origin.y;
            checkRect.size.height = clipRect.size.height;
            NSRange rowsToDraw = [self rowsInRect:checkRect];
            NSUInteger curRow = rowsToDraw.location;
            while(curRow < rowsToDraw.location + rowsToDraw.length) {
                if(curRow % 2 != 0) {
                    // This is an alternate row
                    NSRect rowRect = [self rectOfRow:curRow];
                    rowRect.origin.x = clipRect.origin.x;
                    rowRect.size.width = clipRect.size.width;
                    NSRectFill(rowRect);
                }

                curRow++;
            }

            // Figure out the height of "off the table" rows
            CGFloat rowHeight = [self rowHeight];
            if( ([self gridStyleMask] & NSTableViewSolidHorizontalGridLineMask) == NSTableViewSolidHorizontalGridLineMask
               || ([self gridStyleMask] & NSTableViewDashedHorizontalGridLineMask) == NSTableViewDashedHorizontalGridLineMask) {
                rowHeight += 2.0f; // Compensate for a grid
            }

            // Draw fake rows below the table's last row
            CGFloat virtualRowOrigin = 0.0f;
            NSInteger virtualRowNumber = [self numberOfRows];
            if([self numberOfRows] > 0) {
                NSRect finalRect = [self rectOfRow:[self numberOfRows]-1];
                virtualRowOrigin = finalRect.origin.y + finalRect.size.height;
            }
            while(virtualRowOrigin < clipRect.origin.y + clipRect.size.height) {
                if(virtualRowNumber % 2 != 0) {
                    // This is an alternate row
                    NSRect virtualRowRect = NSMakeRect(clipRect.origin.x,virtualRowOrigin,clipRect.size.width,rowHeight);
                    NSRectFill(virtualRowRect);
                }

                virtualRowNumber++;
                virtualRowOrigin += rowHeight;
            }

            // Draw fake rows above the table's first row
            virtualRowOrigin = -1 * rowHeight;
            virtualRowNumber = -1;
            while(virtualRowOrigin + rowHeight > clipRect.origin.y) {
                if(abs(virtualRowNumber) % 2 != 0) {
                    // This is an alternate row
                    NSRect virtualRowRect = NSMakeRect(clipRect.origin.x,virtualRowOrigin,clipRect.size.width,rowHeight);
                    NSRectFill(virtualRowRect);
                }

                virtualRowNumber--;
                virtualRowOrigin -= rowHeight;
            }
        }
    }
}

3
投票

我不确定最近这是如何添加的,或者它是否像您需要的那样灵活,但我注意到您可以在Xcode 4.6中(可能更早)在Interface Builder中指定“交替”行。

  1. 在Xcode中打开你的笔尖并选择你的NSTableViewNSOutlineView
  2. 在“实用程序”窗格中显示“属性”检查器(⎇⌘4)
  3. 注意Highlight Alternating Rows复选框。


1
投票

没有可设置的属性,但是您可以响应委托方法-tableView:willDisplayCell:forTableColumn:row:并根据行号的均匀度设置单元格的背景颜色。


1
投票

Nate Thornanswer对我来说非常合适。

在这里,为Swift重构:

import Foundation
import Cocoa
import AppKit

public class SubclassedTableView : NSTableView {

    private func
    alternateBackgroundColor() -> NSColor? {
        return NSColor.redColor() // Return any color you like
    }

    public override func
    drawBackgroundInClipRect(clipRect: NSRect) {

        if alternateBackgroundColor() == nil {
            // If we didn't set the alternate colour, fall back to the default behaviour
            super.drawBackgroundInClipRect(clipRect)
        } else {
            // Fill in the background colour
            self.backgroundColor.set()
            NSRectFill(clipRect)

            // Check if we should be drawing alternating coloured rows
            if usesAlternatingRowBackgroundColors {
                // Set the alternating background colour
                alternateBackgroundColor()!.set()

                // Go through all of the intersected rows and draw their rects
                var checkRect = bounds
                checkRect.origin.y = clipRect.origin.y
                checkRect.size.height = clipRect.size.height
                let rowsToDraw = rowsInRect(checkRect)
                var curRow = rowsToDraw.location
                repeat {
                    if curRow % 2 != 0 {
                        // This is an alternate row
                        var rowRect = rectOfRow(curRow)
                        rowRect.origin.x = clipRect.origin.x
                        rowRect.size.width = clipRect.size.width
                        NSRectFill(rowRect)
                    }

                    curRow++
                } while curRow < rowsToDraw.location + rowsToDraw.length

                // Figure out the height of "off the table" rows
                var thisRowHeight = rowHeight
                if gridStyleMask.contains(NSTableViewGridLineStyle.SolidHorizontalGridLineMask)
                   || gridStyleMask.contains(NSTableViewGridLineStyle.DashedHorizontalGridLineMask) {
                    thisRowHeight += 2.0 // Compensate for a grid
                }

                // Draw fake rows below the table's last row
                var virtualRowOrigin = 0.0 as CGFloat
                var virtualRowNumber = numberOfRows
                if numberOfRows > 0 {
                    let finalRect = rectOfRow(numberOfRows-1)
                    virtualRowOrigin = finalRect.origin.y + finalRect.size.height
                }
                repeat {
                    if virtualRowNumber % 2 != 0 {
                        // This is an alternate row
                        let virtualRowRect = NSRect(x: clipRect.origin.x, y: virtualRowOrigin, width: clipRect.size.width, height: thisRowHeight)
                        NSRectFill(virtualRowRect)
                    }

                    virtualRowNumber++
                    virtualRowOrigin += thisRowHeight
                } while virtualRowOrigin < clipRect.origin.y + clipRect.size.height

                // Draw fake rows above the table's first row
                virtualRowOrigin = -1 * thisRowHeight
                virtualRowNumber = -1
                repeat {
                    if abs(virtualRowNumber) % 2 != 0 {
                        // This is an alternate row
                        let virtualRowRect = NSRect(x: clipRect.origin.x, y: virtualRowOrigin, width: clipRect.size.width, height: thisRowHeight)
                        NSRectFill(virtualRowRect)
                    }

                    virtualRowNumber--
                    virtualRowOrigin -= thisRowHeight
                } while virtualRowOrigin + thisRowHeight > clipRect.origin.y
            }
        }
    }
}

1
投票

Swift 4+版本的AlternateRealist's answer

public class AlternateBgColorTableView: NSTableView {
    var alternateBackgroundColor: NSColor? = .red

    override public func drawBackground(inClipRect clipRect: NSRect) {
        // If we didn't set the alternate color, fall back to the default behavior
        guard let alternateBackgroundColor = alternateBackgroundColor else {
            super.drawBackground(inClipRect: clipRect)

            return
        }

        // Fill in the background color
        backgroundColor.set()
        clipRect.fill()

        // Check if we should be drawing alternating colored rows
        if usesAlternatingRowBackgroundColors {
            // Set the alternating background color
            alternateBackgroundColor.set()

            // Go through all of the intersected rows and draw their rects
            var checkRect = bounds
            checkRect.origin.y = clipRect.origin.y
            checkRect.size.height = clipRect.height
            let rowsToDraw = rows(in: checkRect)
            var currentRow = rowsToDraw.location

            repeat {
                if currentRow % 2 != 0 {
                    // This is an alternate row
                    var rowRect = rect(ofRow: currentRow)
                    rowRect.origin.x = clipRect.origin.x
                    rowRect.size.width = clipRect.width
                    rowRect.fill()
                }

                currentRow += 1
            } while currentRow < rowsToDraw.location + rowsToDraw.length

            // Figure out the height of "off the table" rows
            var thisRowHeight = rowHeight

            if gridStyleMask.contains(.solidHorizontalGridLineMask) || gridStyleMask.contains(.dashedHorizontalGridLineMask) {
                thisRowHeight += 2 // Compensate for a grid
            }

            // Draw fake rows below the table's last row
            var virtualRowOrigin: CGFloat = 0
            var virtualRowNumber = numberOfRows

            if numberOfRows > 0 {
                let finalRect = rect(ofRow: numberOfRows - 1)
                virtualRowOrigin = finalRect.origin.y + finalRect.height
            }

            repeat {
                if virtualRowNumber % 2 != 0 {
                    // This is an alternate row
                    let virtualRowRect = NSRect(x: clipRect.origin.x, y: virtualRowOrigin, width: clipRect.width, height: thisRowHeight)
                    virtualRowRect.fill()
                }

                virtualRowNumber += 1
                virtualRowOrigin += thisRowHeight
            } while virtualRowOrigin < clipRect.origin.y + clipRect.size.height

            // Draw fake rows above the table's first row
            virtualRowOrigin = -1 * thisRowHeight
            virtualRowNumber = -1

            repeat {
                if abs(virtualRowNumber) % 2 != 0 {
                    // This is an alternate row
                    let virtualRowRect = NSRect(x: clipRect.origin.x, y: virtualRowOrigin, width: clipRect.width, height: thisRowHeight)
                    virtualRowRect.fill()
                }

                virtualRowNumber -= 1
                virtualRowOrigin -= thisRowHeight
            } while virtualRowOrigin + thisRowHeight > clipRect.origin.y
        }
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.