【问题标题】:NSTableView Row Height based on NSStrings基于 NSStrings 的 NSTableView 行高
【发布时间】:2010-07-09 11:52:13
【问题描述】:

基本上,我有一个带有 1 个列的 NSTableView,并且我在每一行中插入长字符串。但是,并不是所有的字符串都很长,所以我希望每行的高度根据字符串的长度而有所不同。

我发现我需要询问柱子有多宽,然后询问字符串如果柱子那么宽它将占用多少行,然后决定 NSCell 将有多“高” .但我究竟该怎么做呢?我从以下位置获得了列宽:

[[[tableView tableColumns] objectAtIndex:0] width];

但我不知道如何询问 NSString 它将占用多少空间。或者,也许,我应该有更好的方法来做这件事?

提前感谢您的帮助。

【问题讨论】:

    标签: objective-c cocoa nstableview


    【解决方案1】:

    创建一个NSTextFieldCell 实例并匹配其字体/大小/等。到你的列的数据单元格。向它询问-cellSizeForBounds:,传入列所需宽度的矩形,高度较大(FLT_MAX?)。结果应该是一个可以使用其高度的 NSSize。

    如果您有多个多行文本列,则会变得更加棘手,因为您需要考虑该行中的所有单元格,并将最大的单元格作为您的行高。如果您期望平均有很多行,您可能希望缓存这项工作,根据需要对其进行更新,然后在调用行高委托方法时简单地引用它。

    【讨论】:

    • 为什么需要创建一个NSTextFieldCell 的一次性实例?我已经能够毫无问题地在单元本身上调用-cellSizeForBounds:
    • 正确。 :-) 我在用更笼统的术语思考“在真空中获得细胞大小”,而不是使用我的大脑并意识到现有的细胞会做得很好。 :-)
    • @SergeVelikanov 你是什么意思?
    • @JoshuaNozzi,暂时什么都没有——只是不喜欢参考文档。显示一些代码很难吗?我是初学者,我很难理解选择器名称的含义。谢谢
    • 我不知道您是否在刻薄,但在此答案中确实 几乎不需要代码。发布“RTFM”回复并继续前进是一回事,但事实并非如此;它是您执行 OP 要求的唯一 API 调用的直接链接。答案,以其一般形式,对于您想要找到给定宽度的字符串高度的任何情况都非常有用(假设您喜欢标准文本字段的字体)。代码实际上是一行,其中大部分是在第二句中给出的(其余部分将是人为的)。什么时候更多的变成了手握?
    【解决方案2】:

    代码按照上面的答案...

        NSString *string = [[_tableViewDataSourceArray objectAtIndex:rowIndex] 
                                  valueForKey:@"StringToDisplay"];
    
        NSTableColumn *tableColoumn = [aTableView
                                  tableColumnWithIdentifier:@"TableColumnIdentifier"];
    
        if (tableColoumn) 
        {
         NSCell *dataCell = [tableColoumn dataCell];
         [dataCell setWraps:YES];
         [dataCell setStringValue:string];
         NSRect myRect = NSMakeRect(0, 0, [tableColoumn width], CGFLOAT_MAX);
         heightOfRow =  [dataCell cellSizeForBounds:myRect].height;
        }
    

    【讨论】:

      【解决方案3】:

      这是对Robert D'Almeida's answer 的一个小改进(我最初将其作为编辑提交,但由于“将丢失帖子的原始含义或意图”而被拒绝)。我已经添加了方法签名并进行了一些其他的小改动。

      - (CGFloat)tableView:(NSTableView *)aTableView heightOfRow:(NSInteger)row {
          CGFloat heightOfRow = 100; // or some other default value
      
          // get the content for this table cell from the model
          NSString *string = [[_tableViewDataSourceArray objectAtIndex:rowIndex] 
                                    valueForKey:@"StringToDisplay"];
      
          NSTableColumn *tableColumn = [aTableView
                                    tableColumnWithIdentifier:@"TableColumnIdentifier"];
      
          if (tableColumn) {
              NSCell *dataCell = [tableColumn dataCell];
              [dataCell setWraps:YES];
              [dataCell setStringValue:string];
      
              // See how tall it naturally would want to be if given a restricted
              // width, but unbound height
              NSRect myRect = NSMakeRect(0, 0, [tableColumn width], CGFLOAT_MAX);
              heightOfRow = [dataCell cellSizeForBounds:myRect].height;
          }
      
          return heightOfRow;
      }
      

      【讨论】:

        【解决方案4】:

        这是另一种解决方案,在我的情况下效果很好:

        目标-C:

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

        斯威夫特:

        func tableView(tableView: NSTableView, heightOfRow row: Int) -> CGFloat {
            if let log:Log = logsArrayController.arrangedObjects.objectAtIndex(row) as? Log {
                if let string: String = log.message! {
        
                    let someWidth: CGFloat = tableView.frame.size.width
                    let stringAttributes = [NSFontAttributeName: NSFont.systemFontOfSize(12)] //change to font/size u are using
                    let attrString: NSAttributedString = NSAttributedString(string: string, attributes: stringAttributes)
                    let frame: NSRect = NSMakeRect(0, 0, someWidth, CGFloat.max)
                    let tv: NSTextView = NSTextView(frame: frame)
                    tv.textStorage?.setAttributedString(attrString)
                    tv.horizontallyResizable = false
                    tv.sizeToFit()
                    let height: CGFloat = tv.frame.size.height + 20 // + other objects...
        
                    return height
        
                }
        
            }
        
            return 100 //Fail
        }
        

        【讨论】:

        • 谢谢!如果您的 tableview 数据是在 Interface Builder 中使用绑定配置的,那么这个很好。
        • 这种方法在使用自定义单元格时很有帮助,这些单元格在单个列中具有多个可编辑的文本字段,这些文本字段对行高有贡献。由于这不是 Mac 上可变和动态行高中讨论最多的用例,因此这个答案很有价值。
        【解决方案5】:

        我喜欢Robert D'Almeida's answer,但它使用-[tableColumn dataCell],Apple 的文档说“仅对基于单元格的表格视图有效”。

        我的尝试如下。

        在 Interface Builder 中(在 Xcode 中:我目前使用的是 5.1.1),设置一个 NSTableView。

        • 表格视图应将内容模式设置为基于视图
        • 其中一列应具有标识符WrapColumnIdentifier
        • 该列应该包含一个 NSTableCellView,它应该包含一个 NSTextField(要理解下面的代码,您需要知道 NSTextField 包含一个 NSTextFieldCell,它是 NSCell 的子类)
        • NSTextField 对象的 Layout 应该设置为 Wraps
        • NSTextField 对象应该设置一个自动调整大小的掩码,所有六行都启用(红色实心),因此当表格调整表格单元格的大小时,文本字段将调整大小并继续填充单元格。

        这是一个用于该设置的 NSTableViewDelegate 方法。这会导致设置每个表格行的高度,以便“换行列”(包含 NSTextField)显示其文本而不被截断。

        - (CGFloat)tableView:(NSTableView *)aTableView heightOfRow:(NSInteger)aRow {
            NSTableColumn *tableColumn = [aTableView tableColumnWithIdentifier:@"WrapColumnIdentifier"];
        
            // obtain the view that would be used at this position in the table 
            // (ie at this column and row: I'm using this odd form of language so as 
            // to avoid the word "cell" and potential confusion with NSCell), 
            // populated with data from the model
            NSView* view = [self tableView:aTableView viewForTableColumn:tableColumn row:aRow];
            NSAssert([view isKindOfClass:[NSTableCellView class]], @"Expected view used in table to be NSTableCellView");
            NSTableCellView* tableCellView = (NSTableCellView*)view;
        
            // get the NSCell used by the NSTextField at this position in the table
            NSCell* cell = [[tableCellView textField] cell];
        
            // See how tall it naturally would want to be if given a restricted width,
            // but unbound height
            NSRect unboundHeightColumnRect = NSMakeRect(0, 0, [tableColumn width], CGFLOAT_MAX);
            CGFloat cellTextHeight = [cell cellSizeForBounds:unboundHeightColumnRect].height;
        
            // Apple's docs say this method must return a value greater than 0.
            // cellTextHeight might be 0 (eg if the model returns no data at this
            // position in the table).  Use the row height set for the table in IB 
            // as the minimum.
            return MAX(cellTextHeight, [tableView rowHeight]);
        }
        

        【讨论】:

          猜你喜欢
          • 2014-02-07
          • 2022-03-10
          • 2012-06-10
          • 1970-01-01
          • 1970-01-01
          • 2013-03-15
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多