NSTableView dựa trên chế độ xem với các hàng có chiều cao động


84

Tôi có một ứng dụng có chế độ xem NSTableViewtrong đó. Bên trong dạng xem bảng này, tôi có các hàng có các ô có nội dung bao gồm nhiều hàng NSTextFieldđã bật tính năng bọc từ. Tùy thuộc vào nội dung văn bản của NSTextField, kích thước của các hàng cần thiết để hiển thị ô sẽ khác nhau.

Tôi biết rằng tôi có thể triển khai NSTableViewDelegatephương thức - tableView:heightOfRow:để trả về chiều cao, nhưng chiều cao sẽ được xác định dựa trên gói từ được sử dụng trên NSTextField. Việc gói từ của cái NSTextFieldcũng tương tự dựa trên độ rộng của cái NSTextFieldlà… được xác định bởi độ rộng của NSTableView.

Soooo… Tôi đoán câu hỏi của tôi là… một mẫu thiết kế tốt cho việc này là gì? Có vẻ như mọi thứ tôi cố gắng đều trở thành một mớ hỗn độn phức tạp. Vì TableView yêu cầu kiến ​​thức về chiều cao của các ô để sắp xếp chúng ... và NSTextFieldkiến thức cần biết về bố cục của nó để xác định gói từ ... và ô cần kiến ​​thức về gói từ để xác định chiều cao của nó ... đó là một mớ hỗn độn tròn ... và nó khiến tôi phát điên .

Gợi ý?

Nếu nó quan trọng, kết quả cuối cùng cũng sẽ có thể chỉnh sửa NSTextFieldssẽ thay đổi kích thước để điều chỉnh cho phù hợp với văn bản bên trong chúng. Tôi đã có tính năng này hoạt động ở mức chế độ xem, nhưng chế độ xem bảng chưa điều chỉnh độ cao của các ô. Tôi nghĩ rằng một khi tôi giải quyết được vấn đề chiều cao, tôi sẽ sử dụng noteHeightOfRowsWithIndexesChangedphương thức - để thông báo cho chế độ xem bảng là chiều cao đã thay đổi… nhưng sau đó nó vẫn sẽ yêu cầu người đại diện cho biết chiều cao… do đó, câu hỏi của tôi.

Cảm ơn trước!


Nếu cả chiều rộng và chiều cao của chế độ xem có thể thay đổi theo nội dung của chúng, thì việc xác định chúng sẽ phức tạp vì bạn phải lặp lại (nhưng sau đó bạn có thể lưu vào bộ nhớ cache). Nhưng trường hợp của bạn dường như có chiều cao thay đổi cho chiều rộng không đổi. Nếu chiều rộng đã biết (tức là dựa trên chiều rộng của cửa sổ hoặc khung nhìn), thì không có gì ở đây là phức tạp. Tôi thiếu lý do tại sao chiều rộng có thể thay đổi?
Rob Napier

Chỉ chiều cao có thể thay đổi theo nội dung. Và tôi đã giải quyết được vấn đề đó. Tôi có một lớp con NSTextField tự động điều chỉnh chiều cao của nó. Vấn đề là ở chỗ kiến ​​thức về điều chỉnh đó trở lại đại biểu của chế độ xem bảng, để nó có thể cập nhật chiều cao cho phù hợp.
Jiva DeVoe

@Jiva: Tự hỏi bạn đã giải quyết được chưa.
Joshua Nozzi

Tôi đang cố gắng làm điều gì đó tương tự. Tôi thích ý tưởng về một lớp con NSTextField điều chỉnh độ cao của chính nó. Làm thế nào về việc thêm thông báo (đại biểu) về sự thay đổi độ cao vào lớp con đó và giám sát lớp đó với một số lớp thích hợp (nguồn dữ liệu, đại biểu phác thảo, ...) để nhận thông tin về đại cương?
John Velman

Một câu hỏi liên quan nhiều, có câu trả lời giúp tôi nhiều hơn những câu ở đây: NSTableView Row Height dựa trên NSStrings .
Ashley

Câu trả lời:


132

Đây là vấn đề về gà và trứng. Bảng cần biết chiều cao của hàng vì điều đó xác định vị trí của một chế độ xem nhất định. Nhưng bạn muốn một chế độ xem đã có sẵn để bạn có thể sử dụng nó để tìm ra chiều cao của hàng. Vì vậy, cái nào đến trước?

Câu trả lời là giữ thêm NSTableCellView(hoặc bất kỳ chế độ xem nào bạn đang sử dụng làm "chế độ xem ô") xung quanh chỉ để đo chiều cao của chế độ xem. Trong tableView:heightOfRow:phương thức ủy quyền, truy cập mô hình của bạn cho 'hàng' và objectValuebật NSTableCellView. Sau đó, đặt chiều rộng của chế độ xem là chiều rộng của bảng của bạn và (tuy nhiên bạn muốn làm như vậy) tìm ra chiều cao cần thiết cho chế độ xem đó. Trả lại giá trị đó.

Không gọi noteHeightOfRowsWithIndexesChanged:từ trong phương thức ủy nhiệm tableView:heightOfRow:hoặc viewForTableColumn:row:! Điều đó thật tệ, và sẽ gây ra rắc rối lớn.

Để tự động cập nhật chiều cao, thì những gì bạn nên làm là phản hồi văn bản đang thay đổi (thông qua target / action) và tính toán lại chiều cao đã tính của bạn cho chế độ xem đó. Bây giờ, không thay đổi động NSTableCellViewchiều cao của (hoặc bất kỳ chế độ xem nào bạn đang sử dụng làm "chế độ xem ô"). Bảng phải kiểm soát khung của chế độ xem đó và bạn sẽ đấu với chế độ xem bảng nếu bạn cố gắng thiết lập nó. Thay vào đó, trong mục tiêu / hành động của bạn cho trường văn bản nơi bạn đã tính toán chiều cao, hãy gọi noteHeightOfRowsWithIndexesChanged:, điều này sẽ cho phép bảng thay đổi kích thước hàng riêng lẻ đó. Giả sử bạn có thiết lập mặt nạ tự động lưu trữ của mình ngay trên các lượt xem phụ (tức là: lượt xem phụ của NSTableCellView), mọi thứ sẽ ổn định lại kích thước! Nếu không, trước tiên hãy làm việc trên mặt nạ thay đổi kích thước của các lượt xem phụ để làm đúng với chiều cao hàng thay đổi.

Đừng quên rằng hoạt ảnh noteHeightOfRowsWithIndexesChanged:theo mặc định. Để làm cho nó không hoạt hình:

[NSAnimationContext beginGrouping];
[[NSAnimationContext currentContext] setDuration:0];
[tableView noteHeightOfRowsWithIndexesChanged:indexSet];
[NSAnimationContext endGrouping];

Tái bút: Tôi trả lời nhiều câu hỏi được đăng trên Diễn đàn nhà phát triển của Apple hơn là lỗi tràn ngăn xếp.

PSS: Tôi đã viết NSTableView dựa trên chế độ xem


Cảm ơn vì sự trả lời. Tôi đã không nhìn thấy nó ban đầu ... Tôi đã đánh dấu nó là câu trả lời đúng. Các diễn đàn dev rất tuyệt, tôi cũng sử dụng chúng.
Jiva DeVoe 23/02/12

"tìm ra chiều cao cần thiết cho chế độ xem đó. Trả lại giá trị đó." .. Đó là vấn đề của tôi :( Tôi đang sử dụng xem dựa trên tableView, và tôi không có ý tưởng làm thế nào để làm điều đó.!
Mazyod

@corbin Cảm ơn câu trả lời, đây là những gì tôi có trên ứng dụng của mình. Tuy nhiên, tôi đã tìm thấy một vấn đề với nó liên quan đến Mavericks. Vì bạn đã rành về chủ đề này, bạn có phiền kiểm tra câu hỏi của tôi không? Tại đây: stackoverflow.com/questions/20924141/…
Alex

1
@corbin có câu trả lời chuẩn cho điều này, nhưng sử dụng bố cục tự động và các ràng buộc, với NSTableViews? Có một giải pháp tiềm năng với bố cục tự động; tự hỏi liệu điều đó có đủ tốt nếu không có APIHeightForRowAtIndexPath ước tính (không có trong Cocoa)
ZS

3
@ZS: Tôi đang sử dụng Bố cục Tự động và thực hiện câu trả lời của Corbin. Trong tableView:heightOfRow:, tôi thiết lập chế độ xem ô dự phòng của mình với các giá trị của hàng (tôi chỉ có một cột) và trả về cellView.fittingSize.height. fittingSizelà một phương thức NSView tính toán kích thước tối thiểu của khung nhìn thỏa mãn các ràng buộc của nó.
Peter Hosey

43

Điều này trở nên dễ dàng hơn rất nhiều trong macOS 10.13 với .usesAutomaticRowHeights. Thông tin chi tiết có tại đây: https://developer.apple.com/library/content/releasenotes/AppKit/RN-AppKit/#10_13 (Trong phần có tiêu đề "Đèn chiếu sáng hàng tự động NSTableView").

Về cơ bản, bạn chỉ cần chọn của bạn NSTableViewhoặc NSOutlineViewtrong trình chỉnh sửa bảng phân cảnh và chọn tùy chọn này trong Trình kiểm tra kích thước:

nhập mô tả hình ảnh ở đây

Sau đó, bạn đặt nội dung trong của bạn NSTableCellViewcó các ràng buộc trên cùng và dưới cùng đối với ô và ô của bạn sẽ tự động thay đổi kích thước để phù hợp. Không cần mã!

Ứng dụng của bạn sẽ bỏ qua bất kỳ độ cao nào được chỉ định trong heightOfRow( NSTableView) và heightOfRowByItem( NSOutlineView). Bạn có thể xem độ cao nào đang được tính toán cho các hàng bố cục tự động của mình bằng phương pháp này:

func outlineView(_ outlineView: NSOutlineView, didAdd rowView: NSTableRowView, forRow row: Int) {
  print(rowView.fittingSize.height)
}

@tofutim: Nếu hoạt động chính xác với các ô văn bản được bao bọc nếu bạn sử dụng các ràng buộc chính xác và khi bạn đảm bảo cài đặt Chiều rộng ưa thích của từng NSTextField có chiều cao động, được đặt thành Tự động. Xem thêm stackoverflow.com/questions/46890144/…
Ely

Tôi điều @tofutim là đúng, điều này sẽ không hoạt động nếu bạn đặt NSTextView vào TableView, nó cố gắng lưu trữ nó nhưng nó không hoạt động. Nó hoạt động cho các thành phần khác, ví dụ NSImage ..
Albert

Tôi đã sử dụng chiều cao cố định cho một hàng nhưng nó không phù hợp với tôi
Ken Zira

2
Sau vài ngày tìm hiểu lý do tại sao nó không hoạt động với tôi, tôi phát hiện ra: nó CHỈ hoạt động khi TableCellViewKHÔNG thể chỉnh sửa. Không thành vấn đề được kiểm tra trong Thuộc tính [Hành vi: Có thể chỉnh sửa] hoặc Trình kiểm tra ràng buộc [Có thể chỉnh sửa theo thiết lập có điều kiện: Có]
Łukasz

Tôi chỉ muốn nhấn mạnh tầm quan trọng của việc có các giới hạn chiều cao thực tế trong ô bảng của bạn: của tôi thì không, vì vậy kích thước fitSize được tính toán của ô là 0,0 và sự thất vọng xảy ra sau đó.
green_knight

9

Dựa trên câu trả lời của Corbin (btw, cảm ơn đã làm sáng tỏ điều này):

Swift 3, NSTableView dựa trên chế độ xem với bố cục tự động cho macOS 10.11 (trở lên)

Thiết lập của tôi: Tôi có một thiết lập NSTableCellViewđược trình bày bằng cách sử dụng Bố cục Tự động. Nó chứa (bên cạnh các phần tử khác) một nhiều dòng NSTextFieldcó thể có tối đa 2 hàng. Do đó, chiều cao của chế độ xem toàn ô phụ thuộc vào chiều cao của trường văn bản này.

Tôi cập nhật cho chế độ xem bảng để cập nhật chiều cao vào hai lần:

1) Khi chế độ xem bảng thay đổi kích thước:

func tableViewColumnDidResize(_ notification: Notification) {
        let allIndexes = IndexSet(integersIn: 0..<tableView.numberOfRows)
        tableView.noteHeightOfRows(withIndexesChanged: allIndexes)
}

2) Khi đối tượng mô hình dữ liệu thay đổi:

tableView.noteHeightOfRows(withIndexesChanged: changedIndexes)

Điều này sẽ khiến chế độ xem bảng yêu cầu nó ủy quyền cho chiều cao hàng mới.

func tableView(_ tableView: NSTableView, heightOfRow row: Int) -> CGFloat {

    // Get data object for this row
    let entity = dataChangesController.entities[row]

    // Receive the appropriate cell identifier for your model object
    let cellViewIdentifier = tableCellViewIdentifier(for: entity)

    // We use an implicitly unwrapped optional to crash if we can't create a new cell view
    var cellView: NSTableCellView!

    // Check if we already have a cell view for this identifier
    if let savedView = savedTableCellViews[cellViewIdentifier] {
        cellView = savedView
    }
    // If not, create and cache one
    else if let view = tableView.make(withIdentifier: cellViewIdentifier, owner: nil) as? NSTableCellView {
        savedTableCellViews[cellViewIdentifier] = view
        cellView = view
    }

    // Set data object
    if let entityHandler = cellView as? DataEntityHandler {
        entityHandler.update(with: entity)
    }

    // Layout
    cellView.bounds.size.width = tableView.bounds.size.width
    cellView.needsLayout = true
    cellView.layoutSubtreeIfNeeded()

    let height = cellView.fittingSize.height

    // Make sure we return at least the table view height
    return height > tableView.rowHeight ? height : tableView.rowHeight
}

Đầu tiên, chúng ta cần lấy đối tượng mô hình của mình cho hàng ( entity) và định danh dạng xem ô thích hợp. Sau đó, chúng tôi kiểm tra xem chúng tôi đã tạo chế độ xem cho số nhận dạng này chưa. Để làm điều đó, chúng tôi phải duy trì một danh sách với các chế độ xem ô cho từng định danh:

// We need to keep one cell view (per identifier) around
fileprivate var savedTableCellViews = [String : NSTableCellView]()

Nếu không có cái nào được lưu, chúng ta cần tạo (và bộ nhớ cache) một cái mới. Chúng tôi cập nhật chế độ xem ô với đối tượng mô hình của chúng tôi và yêu cầu nó bố trí lại mọi thứ dựa trên chiều rộng chế độ xem bảng hiện tại. Các fittingSizechiều cao sau đó có thể được sử dụng như những tầm cao mới.


Đây là câu trả lời hoàn hảo. Nếu bạn có nhiều cột, bạn sẽ muốn đặt giới hạn thành chiều rộng cột, không phải chiều rộng bảng.
Vojto

Ngoài ra, khi bạn đặt cellView.bounds.size.width = tableView.bounds.size.width, bạn nên đặt lại chiều cao thành một số thấp. Nếu bạn định sử dụng lại chế độ xem giả này, việc đặt nó thành số thấp sẽ "đặt lại" kích thước vừa vặn.
Vojto

7

Đối với bất kỳ ai muốn có thêm mã, đây là giải pháp đầy đủ mà tôi đã sử dụng. Cảm ơn corbin dunn đã chỉ cho tôi đi đúng hướng.

Tôi cần thiết lập chiều cao chủ yếu liên quan đến độ cao NSTextViewcủa tôi NSTableViewCell.

Trong lớp con của NSViewControllertôi, tôi tạm thời tạo một ô mới bằng cách gọioutlineView:viewForTableColumn:item:

- (CGFloat)outlineView:(NSOutlineView *)outlineView heightOfRowByItem:(id)item
{
    NSTableColumn *tabCol = [[outlineView tableColumns] objectAtIndex:0];
    IBAnnotationTableViewCell *tableViewCell = (IBAnnotationTableViewCell*)[self outlineView:outlineView viewForTableColumn:tabCol item:item];
    float height = [tableViewCell getHeightOfCell];
    return height;
}

- (NSView *)outlineView:(NSOutlineView *)outlineView viewForTableColumn:(NSTableColumn *)tableColumn item:(id)item
{
    IBAnnotationTableViewCell *tableViewCell = [outlineView makeViewWithIdentifier:@"AnnotationTableViewCell" owner:self];
    PDFAnnotation *annotation = (PDFAnnotation *)item;
    [tableViewCell setupWithPDFAnnotation:annotation];
    return tableViewCell;
}

Trong IBAnnotationTableViewCellđó của tôi là bộ điều khiển cho ô của tôi (lớp con của NSTableCellView), tôi có một phương pháp thiết lập

-(void)setupWithPDFAnnotation:(PDFAnnotation*)annotation;

thiết lập tất cả các cửa hàng và thiết lập văn bản từ PDFAnnotations của tôi. Bây giờ tôi có thể "dễ dàng" xác định chiều cao bằng cách sử dụng:

-(float)getHeightOfCell
{
    return [self getHeightOfContentTextView] + 60;
}

-(float)getHeightOfContentTextView
{
    NSDictionary *attributes = [NSDictionary dictionaryWithObjectsAndKeys:[self.contentTextView font],NSFontAttributeName,nil];
    NSAttributedString *attributedString = [[NSAttributedString alloc] initWithString:[self.contentTextView string] attributes:attributes];
    CGFloat height = [self heightForWidth: [self.contentTextView frame].size.width forString:attributedString];
    return height;
}

.

- (NSSize)sizeForWidth:(float)width height:(float)height forString:(NSAttributedString*)string
{
    NSInteger gNSStringGeometricsTypesetterBehavior = NSTypesetterLatestBehavior ;
    NSSize answer = NSZeroSize ;
    if ([string length] > 0) {
        // Checking for empty string is necessary since Layout Manager will give the nominal
        // height of one line if length is 0.  Our API specifies 0.0 for an empty string.
        NSSize size = NSMakeSize(width, height) ;
        NSTextContainer *textContainer = [[NSTextContainer alloc] initWithContainerSize:size] ;
        NSTextStorage *textStorage = [[NSTextStorage alloc] initWithAttributedString:string] ;
        NSLayoutManager *layoutManager = [[NSLayoutManager alloc] init] ;
        [layoutManager addTextContainer:textContainer] ;
        [textStorage addLayoutManager:layoutManager] ;
        [layoutManager setHyphenationFactor:0.0] ;
        if (gNSStringGeometricsTypesetterBehavior != NSTypesetterLatestBehavior) {
            [layoutManager setTypesetterBehavior:gNSStringGeometricsTypesetterBehavior] ;
        }
        // NSLayoutManager is lazy, so we need the following kludge to force layout:
        [layoutManager glyphRangeForTextContainer:textContainer] ;

        answer = [layoutManager usedRectForTextContainer:textContainer].size ;

        // Adjust if there is extra height for the cursor
        NSSize extraLineSize = [layoutManager extraLineFragmentRect].size ;
        if (extraLineSize.height > 0) {
            answer.height -= extraLineSize.height ;
        }

        // In case we changed it above, set typesetterBehavior back
        // to the default value.
        gNSStringGeometricsTypesetterBehavior = NSTypesetterLatestBehavior ;
    }

    return answer ;
}

.

- (float)heightForWidth:(float)width forString:(NSAttributedString*)string
{
    return [self sizeForWidth:width height:FLT_MAX forString:string].height ;
}

HeightForWidth: forString: được thực hiện ở đâu?
ZS

Xin lỗi vì điều đó. Đã thêm nó vào câu trả lời. Cố gắng tìm bài đăng SO ban đầu mà tôi nhận được từ đó nhưng không thể tìm thấy.
Sunkas

1
Cảm ơn! Nó gần như hiệu quả với tôi, nhưng nó cho tôi kết quả không chính xác. Trong trường hợp của tôi, chiều rộng mà tôi đang cấp vào NSTextContainer có vẻ sai. Bạn có đang sử dụng bố cục tự động để xác định các lượt xem phụ của NSTableViewCell của mình không? Chiều rộng của "self.contentTextView" đến từ đâu?
ZS

Tôi đã đăng câu hỏi về sự cố của mình ở đây: stackoverflow.com/questions/22929441/…
ZS

3

Tôi đã tìm kiếm một giải pháp trong một thời gian khá dài và đã đưa ra giải pháp sau đây, giải pháp này hoạt động tốt trong trường hợp của tôi:

- (double)tableView:(NSTableView *)tableView heightOfRow:(long)row
{
    if (tableView == self.tableViewTodo)
    {
        CKRecord *record = [self.arrayTodoItemsFiltered objectAtIndex:row];
        NSString *text = record[@"title"];

        double someWidth = self.tableViewTodo.frame.size.width;
        NSFont *font = [NSFont fontWithName:@"Palatino-Roman" size:13.0];
        NSDictionary *attrsDictionary =
        [NSDictionary dictionaryWithObject:font
                                    forKey:NSFontAttributeName];
        NSAttributedString *attrString =
        [[NSAttributedString alloc] initWithString:text
                                        attributes:attrsDictionary];

        NSRect frame = NSMakeRect(0, 0, someWidth, MAXFLOAT);
        NSTextView *tv = [[NSTextView alloc] initWithFrame:frame];
        [[tv textStorage] setAttributedString:attrString];
        [tv setHorizontallyResizable:NO];
        [tv sizeToFit];

        double height = tv.frame.size.height + 20;

        return height;
    }

    else
    {
        return 18;
    }
}

Trong trường hợp của tôi, tôi muốn mở rộng một cột nhất định theo chiều dọc để văn bản tôi hiển thị trên nhãn đó phù hợp với tất cả. Vì vậy, tôi lấy cột được đề cập và lấy phông chữ và chiều rộng từ nó.
Klajd Deda

3

Vì tôi sử dụng tùy chỉnh NSTableCellViewvà tôi có quyền truy cập vào NSTextFieldgiải pháp của tôi là thêm một phương thức vào NSTextField.

@implementation NSTextField (IDDAppKit)

- (CGFloat)heightForWidth:(CGFloat)width {
    CGSize size = NSMakeSize(width, 0);
    NSFont*  font = self.font;
    NSDictionary*  attributesDictionary = [NSDictionary dictionaryWithObject:font forKey:NSFontAttributeName];
    NSRect bounds = [self.stringValue boundingRectWithSize:size options:NSStringDrawingUsesLineFragmentOrigin|NSStringDrawingUsesFontLeading attributes:attributesDictionary];

    return bounds.size.height;
}

@end

Cảm ơn! Bạn là vị cứu tinh của tôi! Đây là cách duy nhất hoạt động chính xác. Tôi đã dành cả ngày để tìm ra điều này.
Tommy

2

Bạn đã xem RowResizableViews chưa? Nó khá cũ và tôi chưa thử nghiệm nó nhưng nó vẫn có thể hoạt động.


2

Đây là những gì tôi đã làm để sửa nó:

Nguồn: Xem tài liệu XCode, trong "row height nstableview". Bạn sẽ tìm thấy mã nguồn mẫu có tên "TableViewVariableRowHeights / TableViewVariableRowHeightsAppDelegate.m"

(Lưu ý: Tôi đang xem cột 1 trong chế độ xem bảng, bạn sẽ phải chỉnh sửa để xem ở chỗ khác)

trong Delegate.h

IBOutlet NSTableView            *ideaTableView;

trong Delegate.m

chế độ xem bảng đại biểu kiểm soát chiều cao hàng

    - (CGFloat)tableView:(NSTableView *)tableView heightOfRow:(NSInteger)row {
    // Grab the fully prepared cell with our content filled in. Note that in IB the cell's Layout is set to Wraps.
    NSCell *cell = [ideaTableView preparedCellAtColumn:1 row:row];

    // See how tall it naturally would want to be if given a restricted with, but unbound height
    CGFloat theWidth = [[[ideaTableView tableColumns] objectAtIndex:1] width];
    NSRect constrainedBounds = NSMakeRect(0, 0, theWidth, CGFLOAT_MAX);
    NSSize naturalSize = [cell cellSizeForBounds:constrainedBounds];

    // compute and return row height
    CGFloat result;
    // Make sure we have a minimum height -- use the table's set height as the minimum.
    if (naturalSize.height > [ideaTableView rowHeight]) {
        result = naturalSize.height;
    } else {
        result = [ideaTableView rowHeight];
    }
    return result;
}

bạn cũng cần điều này để ảnh hưởng đến chiều cao hàng mới (phương pháp được ủy quyền)

- (void)controlTextDidEndEditing:(NSNotification *)aNotification
{
    [ideaTableView reloadData];
}

Tôi hi vọng cái này giúp được.

Lưu ý cuối cùng: điều này không hỗ trợ thay đổi chiều rộng cột.


Bạn rock! :) Cảm ơn bạn.
flagman

4
Thật không may rằng mã mẫu của Apple (hiện được đánh dấu là phiên bản 1.1) sử dụng bảng dựa trên ô, không phải bảng dựa trên chế độ xem (câu hỏi này là về). Các lệnh gọi mã -[NSTableView preparedCellAtColumn:row], mà tài liệu nói "chỉ khả dụng cho các chế độ xem bảng dựa trên NSCell". Sử dụng phương pháp này trên một bảng điểm dựa trên sản lượng sản xuất bản ghi này tại thời gian chạy: "Lỗi Xem Dựa NSTableView: preparedCellAtColumn: row: được gọi hãy đăng nhập một lỗi với backtrace từ nhật ký này, hoặc ngừng sử dụng phương pháp.”.
Ashley

1

Đây là một giải pháp dựa trên câu trả lời của JanApotheker, được sửa đổi vì cellView.fittingSize.heightkhông trả lại chiều cao chính xác cho tôi. Trong trường hợp của tôi, tôi đang sử dụng tiêu chuẩn NSTableCellView,NSAttributedString cho văn bản textField của ô và một bảng cột đơn có các ràng buộc cho textField của ô được đặt trong IB.

Trong bộ điều khiển chế độ xem của tôi, tôi khai báo:

var tableViewCellForSizing: NSTableCellView?

Trong viewDidLoad ():

tableViewCellForSizing = tableView.make(withIdentifier: "My Identifier", owner: self) as? NSTableCellView

Cuối cùng, đối với phương thức ủy nhiệm tableView:

func tableView(_ tableView: NSTableView, heightOfRow row: Int) -> CGFloat {
    guard let tableCellView = tableViewCellForSizing else { return minimumCellHeight }

    tableCellView.textField?.attributedStringValue = attributedString[row]
    if let height = tableCellView.textField?.fittingSize.height, height > 0 {
        return height
    }

    return minimumCellHeight
}

mimimumCellHeightlà một hằng số được đặt thành 30, để sao lưu, nhưng không bao giờ thực sự được sử dụng. attributedStringslà mảng mô hình của tôi vềNSAttributedString .

Điều này hoạt động hoàn hảo cho nhu cầu của tôi. Cảm ơn vì tất cả các câu trả lời trước đó, điều đó đã chỉ cho tôi đúng hướng cho vấn đề khó chịu này.


1
Rất tốt. Một vấn đề. Không thể chỉnh sửa bảng hoặc textfield.fittingSize.height sẽ không hoạt động và sẽ trả về 0. Đặt table.isEditable = false trong viewdidload
jiminybob99

0

Điều này nghe có vẻ giống như một việc mà tôi phải làm trước đây. Tôi ước tôi có thể nói với bạn rằng tôi đã nghĩ ra một giải pháp đơn giản, thanh lịch nhưng, than ôi, tôi đã không làm được. Không phải vì thiếu cố gắng mặc dù. Như bạn đã nhận thấy nhu cầu của UITableView để biết chiều cao trước khi các ô được xây dựng thực sự khiến tất cả có vẻ khá tròn.

Giải pháp tốt nhất của tôi là đẩy logic vào ô, bởi vì ít nhất tôi có thể tách biệt lớp nào cần thiết để hiểu cách các ô được bố trí. Một phương pháp như

+ (CGFloat) heightForStory:(Story*) story

sẽ có thể xác định ô phải cao bao nhiêu. Tất nhiên điều đó liên quan đến việc đo lường văn bản, v.v. Trong một số trường hợp, tôi đã nghĩ ra cách để lưu vào bộ nhớ cache thông tin thu được trong phương pháp này, sau đó có thể được sử dụng khi ô được tạo. Đó là điều tốt nhất tôi nghĩ ra. Đó là một vấn đề gây phẫn nộ mặc dù có vẻ như cần có một câu trả lời tốt hơn.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.