为了账号安全,请及时绑定邮箱和手机立即绑定

基于视图的NSTableView具有动态高度的行

基于视图的NSTableView具有动态高度的行

慕容708150 2019-11-22 12:58:09
我有一个基于视图的应用程序NSTableView。在此表视图中,我有一些行,这些行的单元格的内容由NSTextField启用了自动换行的多行组成。根据的文本内容,NSTextField显示单元格所需的行大小会有所不同。我知道我可以实现该NSTableViewDelegate方法- tableView:heightOfRow:返回高度,但是高度将基于上的自动换行来确定NSTextField。的自动换行NSTextField类似地基于NSTextFieldis的宽度……由的宽度决定NSTableView。太…我想我的问题是……什么是好的设计模式?似乎我尝试的所有操作都变得混乱不堪。由于TableView需要了解单元格的高度才能对其进行布局...并且NSTextField需要了解其布局来确定自动换行...并且单元格需要了解自动换行来确定其高度...这是一个圆形的混乱局面...这让我发疯。有什么建议吗?如果重要的话,最终结果也将具有可编辑的内容NSTextFields,可以调整其大小以适应其中的文本。我已经在视图级别进行此操作,但是tableview尚未调整单元格的高度。我认为一旦解决了高度问题,我将使用- noteHeightOfRowsWithIndexesChanged方法通知表格视图高度已更改……但是仍然要向委托人询问高度……因此,我很困惑。提前致谢!
查看完整描述

3 回答

?
慕妹3146593

TA贡献1820条经验 获得超9个赞

这是鸡和鸡蛋的问题。表格需要知道行高,因为它确定了给定视图的位置。但是,您希望视图已经存在,因此可以使用它来计算行高。那么,哪个先出现?


答案是保留额外的NSTableCellView(或用作“单元格视图”的任何视图)周围,仅用于测量视图的高度。在tableView:heightOfRow:委托方法中,访问模型的“行”并设置objectValueon NSTableCellView。然后将视图的宽度设置为表格的宽度,然后(无论您要执行什么操作)找出该视图所需的高度。返回该值。


请勿noteHeightOfRowsWithIndexesChanged:在委托方法tableView:heightOfRow:或viewForTableColumn:row:!中调用 那是不好的,并且会引起大麻烦。


要动态更新高度,那么您应该做的是响应文本更改(通过目标/动作)并重新计算该视图的计算高度。现在,请勿动态更改NSTableCellView的高度(或任何用作“单元格视图”的视图)。该表必须控制该视图的框架,如果尝试设置该视图,您将与之抗争。相反,在计算高度的文本字段的目标/操作中,调用 noteHeightOfRowsWithIndexesChanged:,这将使表调整该行的大小。假设您已经在子视图(即的子视图NSTableCellView)上设置了自动调整大小的蒙版设置,那么应该可以调整大小!如果不是,请首先对子视图的调整大小蒙版进行操作,以使行高度可变的东西正确无误。


不要忘记noteHeightOfRowsWithIndexesChanged:默认设置动画。要使其不动画,请执行以下操作:


[NSAnimationContext beginGrouping];

[[NSAnimationContext currentContext] setDuration:0];

[tableView noteHeightOfRowsWithIndexesChanged:indexSet];

[NSAnimationContext endGrouping];

PS:我对Apple Dev论坛上发布的问题的回答要多于堆栈溢出。


PSS:我写了基于视图的NSTableView


查看完整回答
反对 回复 2019-11-22
?
慕妹3242003

TA贡献1824条经验 获得超6个赞

根据Corbin的回答(顺便说一句,感谢您对此发表一些看法):


Swift 3,基于视图的NSTableView,带有适用于macOS 10.11(及更高版本)的自动布局


我的设置:我有一个NSTableCellView使用自动版式布局的布局。它包含(除其他元素外)多行NSTextField,最多可包含2行。因此,整个单元格视图的高度取决于此文本字段的高度。


我更新告诉表格视图两次来更新高度:


1)当表格视图调整大小时:


func tableViewColumnDidResize(_ notification: Notification) {

        let allIndexes = IndexSet(integersIn: 0..<tableView.numberOfRows)

        tableView.noteHeightOfRows(withIndexesChanged: allIndexes)

}

2)当数据模型对象更改时:


tableView.noteHeightOfRows(withIndexesChanged: changedIndexes)

这将导致表格视图向其委托要求新的行高。


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

}

首先,我们需要获取模型对象的行(entity)和适当的单元格视图标识符。然后,我们检查是否已经为此标识符创建了视图。为此,我们必须维护一个列表,其中包含每个标识符的单元格视图:


// We need to keep one cell view (per identifier) around

fileprivate var savedTableCellViews = [String : NSTableCellView]()

如果没有保存,则需要创建(并缓存)一个新的。我们使用模型对象更新单元格视图,并告诉它根据当前表视图宽度重新布局所有内容。fittingSize然后可以将该高度用作新的高度。


查看完整回答
反对 回复 2019-11-22
  • 3 回答
  • 0 关注
  • 994 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信