2009-08-05 23 views
48

我有一個NSTableView與幾個文本列。默認情況下,這些列的dataCell是Apple的NSTextFieldCell類的一個實例,它可以做各種奇妙的事情,但它會繪製與單元格頂部對齊的文本,並且我希望文本在單元格中垂直居中。是否有一種「正確」的方式讓NSTextFieldCell繪製垂直居中文本?

NSTextFieldCell中有一個內部標誌,可以用來垂直居中顯示文本,並且它可以很好地工作。但是,由於它是內部標誌,因此它的使用不受Apple的批准,並且在未來的版本中它可能會在沒有警告的情況下消失。我目前使用這個內部標誌,因爲它簡單而有效。顯然,蘋果花了一些時間來實現這個功能,所以我不喜歡重新實現它的想法。

所以;我的問題是這樣的:什麼是正確的方式來實現一些行爲完全像Apple的NStextFieldCell,但繪製垂直居中的文本,而不是頂端對齊?

爲了記錄在案,這裏是我當前的 「解決方案」:

@interface NSTextFieldCell (MyCategories) 
- (void)setVerticalCentering:(BOOL)centerVertical; 
@end 

@implementation NSTextFieldCell (MyCategories) 
- (void)setVerticalCentering:(BOOL)centerVertical 
{ 
    @try { _cFlags.vCentered = centerVertical ? 1 : 0; } 
    @catch(...) { NSLog(@"*** unable to set vertical centering"); } 
} 
@end 

使用方法如下:

[[myTableColumn dataCell] setVerticalCentering:YES]; 
+0

我不認爲try/catch塊在這種情況下是有意義的,因爲_cflags是C結構,而不是Objective C對象。如果在未來的Mac OS X版本中更改此結構,可能會發生各種奇怪的事情,但不會拋出異常。 – 2011-10-24 21:52:53

+0

@Jakob Egger:你可能是對的。我在互聯網上的其他地方找到了解決方案,並按原樣複製它。 – 2011-10-24 22:45:14

+0

你應該接受Jakob Egger的回答。當使用接受的答案中的代碼時,編輯「NSTextFieldCell」時會引起奇怪的毛刺。 Jakob的回答解決了這個問題。 – 2013-01-06 06:27:09

回答

35

其他答案不適用於多行。因此,我最初繼續使用無證文件cFlags.vCentered屬性,但這導致我的應用程序被應用程序商店拒絕。最後我用的馬特·貝爾的解決方案修改後的版本,對於多線,自動換工作,和截短的最後一行:

-(void)drawInteriorWithFrame:(NSRect)cellFrame inView:(NSView *)controlView { 
    NSAttributedString *attrString = self.attributedStringValue; 

    /* if your values can be attributed strings, make them white when selected */ 
    if (self.isHighlighted && self.backgroundStyle==NSBackgroundStyleDark) { 
     NSMutableAttributedString *whiteString = attrString.mutableCopy; 
     [whiteString addAttribute: NSForegroundColorAttributeName 
          value: [NSColor whiteColor] 
          range: NSMakeRange(0, whiteString.length) ]; 
     attrString = whiteString; 
    } 

    [attrString drawWithRect: [self titleRectForBounds:cellFrame] 
        options: NSStringDrawingTruncatesLastVisibleLine | NSStringDrawingUsesLineFragmentOrigin]; 
} 

- (NSRect)titleRectForBounds:(NSRect)theRect { 
    /* get the standard text content rectangle */ 
    NSRect titleFrame = [super titleRectForBounds:theRect]; 

    /* find out how big the rendered text will be */ 
    NSAttributedString *attrString = self.attributedStringValue; 
    NSRect textRect = [attrString boundingRectWithSize: titleFrame.size 
               options: NSStringDrawingTruncatesLastVisibleLine | NSStringDrawingUsesLineFragmentOrigin ]; 

    /* If the height of the rendered text is less then the available height, 
    * we modify the titleRect to center the text vertically */ 
    if (textRect.size.height < titleFrame.size.height) { 
     titleFrame.origin.y = theRect.origin.y + (theRect.size.height - textRect.size.height)/2.0; 
     titleFrame.size.height = textRect.size.height; 
    } 
    return titleFrame; 
} 

(此代碼假定ARC;添加一個自動attrString.mutableCopy後,如果使用手動內存管理)

+0

這對我有用,它是一個非常好的實現 - 謝謝。 – ioquatix 2012-05-22 04:24:11

+0

這工作得很好。接受的答案在編輯單元時引起了一個奇怪的故障。 – 2013-01-06 06:25:27

+3

順便說一下,是否可以在正在編輯的文本中居中?我的'NSTextFieldCell'是多行,當用戶雙擊文本進行編輯時,它會回到頂部直到編輯完成。 – 2013-01-06 19:23:11

29

重寫的NSCell的-titleRectForBounds:應該這樣做 - 那就是負責告訴的方法細胞在哪裏繪製其文字:

- (NSRect)titleRectForBounds:(NSRect)theRect { 
    NSRect titleFrame = [super titleRectForBounds:theRect]; 
    NSSize titleSize = [[self attributedStringValue] size]; 
    titleFrame.origin.y = theRect.origin.y + (theRect.size.height - titleSize.height)/2.0; 
    return titleFrame; 
} 

- (void)drawInteriorWithFrame:(NSRect)cellFrame inView:(NSView *)controlView { 
    NSRect titleRect = [self titleRectForBounds:cellFrame]; 
    [[self attributedStringValue] drawInRect:titleRect]; 
} 
+0

這似乎是一個有前途的想法,但它不適合我。我創建了'NSTextFieldCell'的子類,複製了你的代碼,並在我的'NSTableView'中爲單元格使用了自定義類,但'titleRectForBounds'方法從不被調用。 – 2009-08-06 06:47:03

+3

啊,我忘了NSTextFieldCell基本上在於它的文檔 - 你說得對,默認情況下NSTextFieldCell不使用-titleRectForBounds :.我已經更新了我的覆蓋-drawInteriorWithFrame:inView的答案:以便在正確的位置繪製文本。 – 2009-08-06 10:13:05

+0

很好完成。這就像一個魅力! – 2009-08-06 15:19:04

4

FYI ,這個效果很好,雖然當你編輯單元格時,我還沒有設法讓它保持居中......我有時會有大量文本的單元格,並且如果文本高度大於此值,這些代碼可能會導致它們未對齊。它試圖垂直居中在電池下面是我的修改方法:

- (NSRect)titleRectForBounds:(NSRect)theRect 
{ 
    NSRect titleFrame = [super titleRectForBounds:theRect]; 
    NSSize titleSize = [[self attributedStringValue] size]; 
    // test to see if the text height is bigger then the cell, if it is, 
    // don't try to center it or it will be pushed up out of the cell! 
    if (titleSize.height < theRect.size.height) { 
     titleFrame.origin.y = theRect.origin.y + (theRect.size.height - titleSize.height)/2.0; 
    } 
    return titleFrame; 
} 
4

對於任何試圖此使用馬特·鮑爾的drawInteriorWithFrame:inView:方法,這將不再繪製背景,如果你設置你的畫之一。爲了解決這一沿線的

[[NSColor lightGrayColor] set]; 
NSRectFill(cellFrame); 

講一下你的drawInteriorWithFrame:inView:方法的開始。

2

雖然這是很老的問題...

相信NSTableView的執行默認樣式旨在嚴格遵守所有相同尺寸&字體單行文字顯示。

在這種情況下,我建議,

  1. 設置字體。
  2. 調整rowHeight

也許你會得到悄悄密行。然後,通過設置intercellSpacing給他們填充。

例如,

core_table_view.rowHeight    = [NSFont systemFontSizeForControlSize:(NSSmallControlSize)] + 4; 
    core_table_view.intercellSpacing  = CGSizeMake(10, 80); 

在這裏你將有兩個屬性調整得到。

enter image description here

這不會爲多行文本工作,但也足夠快垂直中心非常好,如果你不需要多行支持。

+0

這對於單行單元格來說是合理的解決方案,可能涵蓋大多數用例。謝謝! – 2014-12-01 19:35:29

1

我有同樣的問題,這裏是解決方案,我所做的:

1)在Interface Builder中,選擇您的NSTableCellView。確保它與Size Inspector中的行高一樣大。例如,如果你的行高爲32,讓你的細胞高度32

2)確保你的細胞處於有利位置你行(我的意思是可見的)

3)選擇您的裏面的TextField和去你的尺寸檢查

4)你應該看到「安排」項,然後選擇「垂直居中集裝箱」

- > TextField的將中心本身在細胞

0

號正確的方法是將字段放在另一個視圖中並使用aut o佈局或父視圖的佈局來定位它。

+0

好的 - 但是我怎麼讓字段調整大小(改變它的高度)來匹配文本?沒有這一點,我會有一個很好的居中文本字段,但字段內的文本仍然是頂部對齊的,所以文本會出現在父視圖中心的上方。 – 2014-12-01 19:34:04

+0

這絕對是正確的答案。允許NSTextField依賴其內在大小(根據您的喜好調整字體大小,這將對應於內在大小的變化),然後將其作爲子視圖添加到容器視圖,該容器視圖將根據包含文本字段的任何內容並且這將構成文本字段相對於整個空間的固有尺寸。 – Asher 2015-11-05 07:45:58

+0

@Asher,實際上不是,更改字體大小不會導致字段調整大小:https://www.dropbox.com/s/9b4vgcp7kuujll2/Screenshot%202016-03-01%2012.02.26.png?dl=0 – 2016-03-01 17:02:52