objective-c cocoa macos interface-builder nstableview

objective c - Cambiar NSTableView colores de fila alternativos



objective-c cocoa (7)

Encontré una mejor manera de hacerlo here . Ese método anula el método highlightSelectionInClipRect: en una subclase NSTableView para que pueda usar el color que desee para las filas alternas. No es tan intrincado como usar una categoría de NSColor, y solo afecta las vistas de tabla que elija.

Estoy usando la opción "Filas alternas" en Interface Builder para obtener colores de fila alternativos en un NSTableView. ¿Hay alguna manera de cambiar los colores de las filas alternas?


La answer funcionó perfectamente para mí.

Aquí está, refactorizado para 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 } } } }


No estoy seguro de cómo se agregó recientemente, o si es tan flexible como lo necesita, pero me di cuenta de que puede especificar filas "Alternantes" en Interface Builder en Xcode 4.6 (y posiblemente antes).

  1. Abra su pluma en Xcode y seleccione su NSTableView o NSOutlineView
  2. Mostrar el inspector de atributos en el panel Utilidades (⎇⌘4)
  3. Observe la casilla de verificación Highlight Alternating Rows .

No hay una propiedad configurable para esto, sin embargo, puede responder al método delegado -tableView:willDisplayCell:forTableColumn:row: y establecer el color de fondo de la celda según la uniformidad del número de fila.


Quería una solución que funcionara como la NSTableView normal, que incluye soporte para desplazamiento elástico y eso, así que creé una subclase NSTableView que tiene una propiedad NSColor* llamada alternateBackgroundColor , y luego -drawBackgroundColorInClipRect: método -drawBackgroundColorInClipRect: método así:

- (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; } } } }


Subclasificé NSTableView e implementé drawRow: clipRect: como esto ...

- (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]; }

Parece funcionar, pero es tan simple que me pregunto si me estoy perdiendo algo.


Si desea utilizar una forma no documentada, NSColor una categoría de NSColor y anule _blueAlternatingRowColor esta manera:

@implementation NSColor (ColorChangingFun) +(NSColor*)_blueAlternatingRowColor { return [NSColor redColor]; } @end

o para cambiar ambos colores, anule controlAlternatingRowBackgroundColors para devolver un conjunto de colores que desee alternar.

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