Имитируйте "заполнитель" при перетаскивании NSView и избегайте мерцания, когда пользователь отменяет перетаскивание
У меня есть базовое приложение Cocoa Mac с представлением, которое содержит подпредставление. Подпредставление можно перетаскивать, и я бы хотел, чтобы у пользователя создалось впечатление, что он фактически перемещает представление, оставляя заполнитель в его исходном местоположении, в то время как при перетаскивании.
Подход по умолчанию заключается в создании нового NSDraggingItem
со снимком подпредставления, чтобы при перетаскивании вида отображалось, что вид действительно перемещается.
По умолчанию подпредставление остается видимым в своем первоначальном расположении, поэтому на экране могут отображаться два экземпляра:
Теперь я хотел бы дать пользователю иллюзию "выбора вида" и его перемещения, оставляя заполнитель в исходном положении. Я делаю это, меняя цвет фона подпредставления на серый, когда вид перетаскивается. Вот результат:
Практически идеально! За исключением того, что, когда перетаскивание отменено, и представление возвращается в исходное положение, оно мигает один раз.
Это потому, что я возвращаю цвет фона подпредставления обратно в NSDraggingSource.draggingSession(_ session: NSDraggingSession, endedAt screenPoint: NSPoint, operation: NSDragOperation)
который, в свою очередь, называется крошечной дробью после завершения анимации перетаскивания.
Вот порядок событий:
- Пользователь начинает перетаскивать подпредставление
- Снимок представления берется и используется для сеанса перетаскивания
- Цвет фона представления изменен на темно-серый, чтобы имитировать "заполнитель"
- Пользователь перетаскивает вид и нажимает клавишу Esc, чтобы отменить перетаскивание.
- Снимок изображения возвращается в исходное положение
- После возврата изображение снимка исчезает над фактическим представлением элемента (анимация, предоставляемая системой)
dragginSession(endedAt)
вызывается и фон меняется обратно
Моя проблема в том, что мне нужно восстановить исходный цвет фона сразу после #5, а не после шага #6. Есть ли способ получить уведомление прямо, когда заканчивается анимация перетаскивания?
Исходный код:
class HomebaseView: NSView, NSDraggingSource {
@IBOutlet var itemView:ItemView!
override func mouseDragged(with event: NSEvent) {
startDraggingItem(with: event)
}
func draggingSession(_ session: NSDraggingSession, willBeginAt screenPoint: NSPoint) {
itemView.isBeingDragged = true
}
func draggingSession(_ session: NSDraggingSession, endedAt screenPoint: NSPoint, operation: NSDragOperation) {
itemView.isBeingDragged = false
}
func draggingSession(_ session: NSDraggingSession, sourceOperationMaskFor context: NSDraggingContext) -> NSDragOperation {
return .copy
}
private func startDraggingItem(with event:NSEvent) {
let item = itemView!
let pasteboardItem = NSPasteboardItem()
let draggingItem = NSDraggingItem(pasteboardWriter: pasteboardItem)
let itemFrame = item.convert(item.bounds, to: self)
draggingItem.setDraggingFrame(itemFrame, contents: item.snapshot())
beginDraggingSession(with: [draggingItem], event: event, source: self)
}
}
extension NSView {
public func snapshot() -> NSImage {
let pdfData = dataWithPDF(inside: bounds)
let image = NSImage(data: pdfData)
return image ?? NSImage()
}
}
РЕДАКТИРОВАТЬ:
В качестве доказательства того, что это должно быть как-то возможно, приведу анимацию из Keynote. Это немного сложно увидеть, но слайд "скользит" назад без затухающей анимации в своем начале.