Отслеживание позиции NSCell при изменении
У меня есть NSTableView
и хотите отследить положение его содержимого NSCell
s, когда tableView прокручивается пользователем.
Я не мог найти ничего полезного. Было бы здорово, если бы кто-то мог привести меня в правильном направлении!
РЕДАКТИРОВАТЬ:
Благодаря @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) для Copy on Scroll
в IB.
Но когда я проверяю x и y вида / ячеек frame
(в viewWillDraw
моего подкласса MyCustomTableCellView) он остается 0, 0
,
3 ответа
Я просто решил проблему самостоятельно.
Просто установите вид содержимого postsBoundsChangedNotifications
в true
и добавил наблюдателя в NotificationCenter для NSViewBoundsDidChange
, Работает как шарм!
Обновление на основе отредактированного вопроса:
Во-первых, просто чтобы вы знали, NSTableCellView
это не NSCell
ни подкласс этого. Когда вы используете таблицу на основе представления, вы не используете NSCell
для просмотра ячеек.
Кроме того, вид frame
всегда относительно границ своего непосредственного супервизора. Это не абсолютная позиция. И суперпредставление представления ячейки не является представлением таблицы или представлением прокрутки. Виды ячеек находятся внутри видов строк. Вот почему ваш вид ячейки находится в 0, 0.
Вы могли бы использовать NSTableView
"s frameOfCell(atColumn:row:)
чтобы определить, где данное представление ячейки находится в представлении таблицы. Я все еще не думаю, что это хороший подход. Пожалуйста, смотрите последний абзац моего оригинального ответа ниже:
Оригинальный ответ:
Табличные представления не "содержат" связку NSCell
как вы думаете. Также, NSCell
у них нет позиции. Весь смысл NSCell
составные представления основаны на том, что они намного легче, чем архитектура, в которой для каждой ячейки используется отдельный объект.
Обычно есть один NSCell
для каждого столбца таблицы. Когда табличное представление должно нарисовать ячейки в столбце, оно настраивает NSCell
с данными для одной ячейки и говорит ему рисовать в позиции этой ячейки. Затем он настраивает тот же NSCell
с данными для следующей ячейки и говорит ей рисовать на следующей позиции. И т.п.
Чтобы сделать то, что вы хотите, вы можете настроить представление прокрутки, чтобы не копировать при прокрутке. Затем в табличном представлении будет предложено рисовать все, когда оно прокручивается. Затем вы бы реализовать tableView(_:willDisplayCell:for:row:)
метод делегата и применение альфа-значения к ячейкам в верхнем и нижнем краях представления прокрутки.
Но это, вероятно, не очень хороший подход.
Я думаю, что вам может повезти, добавив плавающие подпредставления в представление прокрутки, которые являются частично прозрачными, с градиентом от полностью непрозрачного до полностью прозрачного в цвете фона. Таким образом, вместо того, чтобы ячейки исчезали и пропускали фон, вы помещаете другой вид сверху, который пропускает только часть ячеек.
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)
}
}
}
}
}
Результат: