【问题标题】:Growing NSTableView Row Height不断增长的 NSTableView 行高
【发布时间】:2014-10-11 22:24:27
【问题描述】:

我在 MacOSX 应用程序中有一个基于视图的 NSTableView,它可以很好地构造数据。我想实现 NSTableView 以使行高随着输入到其中一个 NSTextView 中的数据内容而增长。我已经将 NSTextView 子类化为与用户文本一起“增长”,但问题是在 TableView 中嵌入字段会导致字段被剪切。

有人对如何实现不断增长的行大小有任何建议吗?

【问题讨论】:

    标签: macos cocoa nstableview nstextview


    【解决方案1】:

    您需要在表视图委托中实现-tableView:heightOfRow: 并返回行的适当高度。此外,您需要监视文本视图的高度变化,并在它们中的任何一个变化时在表格视图上调用-noteHeightOfRowsWithIndexesChanged:。要监控文本视图的高度,观察他们将发布的NSViewFrameDidChangeNotification 就足够了。

    (如果您通常在 UI 中使用自动布局,我认为您将不得不在 translatesAutoresizingMaskIntoConstraints 上保留文本视图,手动放置它们,并根据需要设置它们的自动调整大小掩码。然后,您将避免设置对它们的任何其他约束。这是因为您需要由文本布局管理器设置框架,而不是通过自动布局。)

    【讨论】:

    • 谢谢 ken,这是一个巨大的帮助。我已经实现了 -tableView:heightOfRow: 但我在监控文本视图时遇到了问题。使用 IB 中的 autoLayout 功能让我得到了我所追求的扩展 textView(感谢这一点 - 一个比我最初拥有的更清洁的解决方案),但我仍然在监控文本视图方面遇到问题。您能否详细说明 noteHeighOfRowsWithIndexesChanged: 和 NSViewFrameDidChangeNotification 的使用?
    • 什么方面给你带来了麻烦?每次向表中添加文本视图时,都将控制器对象作为NSViewFrameDidChangeNotification 的观察者添加到[NSNotificationCenter defaultCenter],文本视图位于发布“对象”。然后,在您的通知处理代码中,您使用-[NSTableView rowForView:] 查找哪一行对应于其框架更改的视图(通知的object)。然后在表视图上调用-noteHeightOfRowsWithIndexesChanged:,传递一个包含行索引的索引集。移除视图时停止观察。
    • 好的,我认为我没有正确理解这一点。我实现了 -noteHeightofRowsWithIndexesChanged: 但它似乎没有被调用。我需要在我的 AppDelegate 中初始化 NSNotificationCentre 吗?
    • 你没有实现-noteHeightOfRowsWithIndexesChanged:。这是NSTableView 上的一种方法。当您需要告诉表格视图某些行的高度已更改时,您调用该方法,以便它知道向您的委托询问新的高度。
    • 感谢您的帮助肯。我会继续玩它,看看我能不能解决它。
    【解决方案2】:

    我已经设法在 Swift 3 中实现了这一点(在 this 很棒的提示和 thisthis SO 答案的帮助下):

    确保NSTableView 中的表格视图单元格与采用NSTextFieldDelegate 协议的子类/视图控制器有委托连接。

    还给它这些约束以确保它根据行的高度调整大小:

    在委托中使用以下代码:

    var editedString: String? = nil
    var textCellForHeight: NSTextFieldCell = NSTextFieldCell.init()
    
    func control(_ control: NSControl, textShouldBeginEditing fieldEditor: NSText) -> Bool {
        editedString = fieldEditor.string ?? ""
        return true
    }
    
    func control(_ control: NSControl, textShouldEndEditing fieldEditor: NSText) -> Bool {
        editedString = nil
        return true
    }   
    
     func control(_ control: NSControl, textView: NSTextView, doCommandBy commandSelector: Selector) -> Bool {
        if commandSelector == #selector(insertNewline(_:)) {
             textView.insertNewlineIgnoringFieldEditor(self)
             editedString = textView.string ?? ""
             //The NSAnimationContext lines get rid of the animation that normally happens when the height changes
             NSAnimationContext.beginGrouping()
             NSAnimationContext.current().duration = 0
             myTableView.noteHeightOfRows(withIndexesChanged: IndexSet.init(integer: selected))
             NSAnimationContext.endGrouping()
             myTable.needsDisplay = true
             return true
        }
        return false
    }
    
    func tableView(_ tableView: NSTableView, heightOfRow row: Int) -> CGFloat {
        if let temp = editedString { //we know it’s currently being edited if it’s not nil
            textCellForHeight.stringValue = temp
            //in my case, there was a specific table column that I knew would be edited
            //you might need to decide on the column width another way.
            let column = myTable.tableColumns[myTable.column(withIdentifier: “TheColumnThatsBeingEdited”)]
            let frame: NSRect = NSMakeRect(0, 0, column.width, CGFloat.greatestFiniteMagnitude)
            return textCellForHeight.cellSize(forBounds: frame).height
        }
      return yourStandardHeightCGFloat
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2023-04-07
      • 2016-07-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多