[英]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.