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

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

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

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

Default behavior

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

enter image description here

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

Это потому, что я возвращаю фоновый цвет подпредставления обратно в 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.Это немного сложно увидеть, но слайд «скользит» назад без анимации затухания в своем начале.

Keynote example

...