[英]Tracking the position of a NSCell on change
我有一个NSTableView
并希望在用户滚动tableView时跟踪其包含NSCell
的位置。
我找不到任何帮助。 如果有人可以引导我朝正确的方向发展,那就太好了!
编辑:
感谢@Ken Thomases和@Code Different ,我才意识到我正在使用基于视图的tableView,它使用tableView(_ tableView:viewFor tableColumn:row:)
,该方法返回一个NSView。
但是,该NSView本质上是一个NSCell。
let cell = myTableView.make(withIdentifier: "customCell", owner: self) as! MyCustomTableCellView // NSTableCellView
所以我真的希望我最初的问题不会引起误解。 我仍在寻找一种方法来跟踪各个单元格/视图的位置 。
我将NSScrollView
(包含tableView)的行为设置为IB中的Copy on Scroll
。
但是,当我检查视图/单元格frame
的x和y(在MyCustomTableCellView子类的viewWillDraw
内)时,它仍然0, 0
。
首先,您已经知道, NSTableCellView
不是NSCell
也不是它的子类。 使用基于视图的表时,单元格视图未使用NSCell
。
同样,视图的frame
始终相对于其直接父视图的边界。 这不是绝对立场。 单元格视图的超级视图不是表视图也不是滚动视图。 单元格视图位于行视图内部。 这就是为什么单元格视图的原点位于0,0。
您可以使用NSTableView
的frameOfCell(atColumn:row:)
来确定给定单元格视图在表视图中的位置。 不过,我仍然认为这不是一个好方法。 请参阅以下原始答案的最后一段:
表格视图并不像您认为的那样“包含”一堆NSCell
。 同样, NSCell
没有位置。 基于NSCell
的复合视图的全部要点是,它们比为每个单元格使用单独对象的体系结构轻得多。
通常,每个表列都有一个NSCell
。 当表格视图需要在列中绘制单元格时,它将使用一个单元格的数据配置该列的NSCell
并告诉它在该单元格的位置绘制。 然后,它使用下一个单元格的数据配置相同的NSCell
,并告诉它在下一个位置绘制。 等等。
要执行所需的操作,可以将滚动视图配置为不在滚动时复制。 然后,无论何时滚动,都将要求表格视图绘制所有内容。 然后,您将实现tableView(_:willDisplayCell:for:row:)
委托方法,并将alpha值应用于滚动视图顶部和底部边缘的单元格。
但这可能不是一个好方法。
我想您可以通过向滚动视图添加部分透明的浮动子视图来获得更好的运气,该子视图的背景颜色从完全不透明到完全透明。 因此,您可以在顶部放置另一个视图,以仅使部分单元格显示出来,而不是使单元格消失并让背景显示出来。
NSScrollView
不使用委托。 它使用通知中心通知观察者已发生更改。 下面的解决方案假定垂直滚动。
override func viewDidLoad() {
super.viewDidLoad()
// Observe the notification that the scroll view sends out whenever it finishes a scroll
let notificationName = NSNotification.Name.NSScrollViewDidLiveScroll
NotificationCenter.default.addObserver(self, selector: #selector(scrollViewDidScroll(_:)), name: notificationName, object: scrollView)
// Post an intial notification to so the user doesn't have to start scrolling to see the effect
scrollViewDidScroll(Notification(name: notificationName, object: scrollView, userInfo: nil))
}
// Whenever the scroll view finished scrolling, we will start coloring the rows
// based on how much they are visible in the scroll view. The idea is we will
// perform hit testing every n-pixel in the scroll view to see what table row
// lies there and change its color accordingly
func scrollViewDidScroll(_ notification: Notification) {
// The data's part of a table view begins with at the bottom of the table's header
let topEdge = tableView.headerView!.frame.height
let bottomEdge = scrollView.bounds.height
// We are going to do hit-testing every 10 pixel. For best efficiency, set
// the value to your typical row's height
let step = CGFloat(10.0)
for y in stride(from: topEdge, to: bottomEdge, by: step) {
let point = NSPoint(x: 10, y: y) // the point, in the coordinates of the scrollView
let hitPoint = scrollView.convert(point, to: tableView) // the same point, in the coordinates of the tableView
// The row that lies that the hitPoint
let row = tableView.row(at: hitPoint)
// If there is a row there
if row > -1 {
let rect = tableView.rect(ofRow: row) // the rect that contains row's view
let rowRect = tableView.convert(rect, to: scrollView) // the same rect, in the scrollView's coordinates system
let visibleRect = rowRect.intersection(scrollView.bounds) // the part of the row that visible from the scrollView
let visibility = visibleRect.height / rowRect.height // the percentage of the row that is visible
for column in 0..<tableView.numberOfColumns {
// Now iterate through every column in the row to change their color
if let cellView = tableView.view(atColumn: column, row: row, makeIfNecessary: true) as? NSTableCellView {
let color = cellView.textField?.textColor
// The rows in a typical text-only tableView is 17px tall
// It's hard to spot their grayness so we exaggerate the
// alpha component a bit here:
let alpha = visibility == 1 ? 1 : visibility / 3
cellView.textField?.textColor = color?.withAlphaComponent(alpha)
}
}
}
}
}
结果:
我只是自己解决了这个问题。
只需将内容视图postsBoundsChangedNotifications
设置为true
,并向NotificationCenter添加一个用于NSViewBoundsDidChange
的观察者。 奇迹般有效!
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.