Имитируйте "заполнитель" при перетаскивании NSView и избегайте мерцания, когда пользователь отменяет перетаскивание

У меня есть базовое приложение Cocoa Mac с представлением, которое содержит подпредставление. Подпредставление можно перетаскивать, и я бы хотел, чтобы у пользователя создалось впечатление, что он фактически перемещает представление, оставляя заполнитель в его исходном местоположении, в то время как при перетаскивании.

Подход по умолчанию заключается в создании нового NSDraggingItem со снимком подпредставления, чтобы при перетаскивании вида отображалось, что вид действительно перемещается.

По умолчанию подпредставление остается видимым в своем первоначальном расположении, поэтому на экране могут отображаться два экземпляра:

Теперь я хотел бы дать пользователю иллюзию "выбора вида" и его перемещения, оставляя заполнитель в исходном положении. Я делаю это, меняя цвет фона подпредставления на серый, когда вид перетаскивается. Вот результат:

Практически идеально! За исключением того, что, когда перетаскивание отменено, и представление возвращается в исходное положение, оно мигает один раз.

Это потому, что я возвращаю цвет фона подпредставления обратно в NSDraggingSource.draggingSession(_ session: NSDraggingSession, endedAt screenPoint: NSPoint, operation: NSDragOperation) который, в свою очередь, называется крошечной дробью после завершения анимации перетаскивания.

Вот порядок событий:

  1. Пользователь начинает перетаскивать подпредставление
  2. Снимок представления берется и используется для сеанса перетаскивания
  3. Цвет фона представления изменен на темно-серый, чтобы имитировать "заполнитель"
  4. Пользователь перетаскивает вид и нажимает клавишу Esc, чтобы отменить перетаскивание.
  5. Снимок изображения возвращается в исходное положение
  6. После возврата изображение снимка исчезает над фактическим представлением элемента (анимация, предоставляемая системой)
  7. 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. Это немного сложно увидеть, но слайд "скользит" назад без затухающей анимации в своем начале.

0 ответов

Другие вопросы по тегам