web-dev-qa-db-ja.com

NSTextFieldCellに垂直方向の中央に配置されたテキストを描画させる「正しい」方法はありますか?

いくつかのテキスト列を持つNSTableViewがあります。デフォルトでは、これらの列のdataCellはAppleのNSTextFieldCellクラスのインスタンスであり、あらゆる種類のすばらしいことを実行しますが、セルの上部に揃えてテキストを描画します。セルの垂直方向の中央に配置されるテキスト。

NSTextFieldCellには、テキストを垂直方向に中央揃えするために使用できる内部フラグがあり、美しく機能します。ただし、これは内部フラグであるため、その使用はAppleによって認可されておらず、将来のリリースでは警告なしに単に消える可能性があります。この内部フラグは、シンプルで効果的であるため、現在使用しています。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];
51
e.James

他の回答は複数行に対して機能しませんでした。したがって、私は最初は文書化されていないcFlags.vCenteredプロパティですが、そのため、アプリがアプリストアから拒否されました。最終的に、複数行、ワードラップ、および切り捨てられた最後の行で機能するMattBellのソリューションの修正バージョンを使用しました。

-(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の後に自動解放を追加します)

36
Jakob Egger

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];
}
31
Matt Ball

MattBallのdrawInteriorWithFrame:inView:メソッドを使用してこれを試みた場合、セルに背景を描画するように設定していると、背景は描画されなくなります。これを解決するには、の線に沿って何かを追加します

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

drawInteriorWithFrame:inView:メソッドの先頭に移動します。

5
Greg Sexton

参考までに、これはうまくいきますが、セルを編集するときに中央に配置することはできませんでした...大量のテキストを含むセルがある場合があります。このコードにより、テキストの高さが大きい場合にセルがずれることがあります次に、垂直方向の中央に配置しようとしているセルです。変更したメソッドを次に示します。

- (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
coradine

これはかなり古い質問ですが...

NSTableView実装のデフォルトスタイルは、すべて同じサイズとフォントの1行のテキスト表示に厳密に対応していると思います。

その場合は、

  1. フォントを設定します。
  2. rowHeightを調整します。

多分あなたは静かに密集した列を得るでしょう。次に、intercellSpacingを設定してパディングを行います。

例えば、

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

ここでは、2つのプロパティ調整で得られるものを示します。

enter image description here

これは複数行のテキストでは機能しませんが、複数行のサポートが必要ない場合は、垂直方向の中央揃えをすばやく行うには十分です。

2
Eonil

いいえ。正しい方法は、フィールドを別のビューに配置し、自動レイアウトまたはその親ビューのレイアウトを使用して配置することです。

1
Frank Krueger

私は同じ問題を抱えていました、そしてここに私がした解決策があります:

1)Interface Builderで、NSTableCellViewを選択します。サイズインスペクターの行の高さと同じ大きさであることを確認してください。たとえば、行の高さが32の場合、セルの高さを32にします。

2)あなたの細胞があなたの列にうまく配置されていることを確認してください(つまり、目に見えることを意味します)

3)セル内のTextFieldを選択し、サイズインスペクターに移動します

4)「配置」項目が表示され、「コンテナ内で垂直に中央揃え」を選択する必要があります

-> TextFieldはセルの中央に配置されます

1
AllezLesBleus