簡體   English   中英

SwiftUI 拖放重新排序 - 檢測 object 釋放

[英]SwiftUI Drag and Drop reorder - detect object release

根據此解決方案,我實現了一個簡單的拖放操作以重新排序 VStack/Scrollview 中的項目

我將當前拖動的項目存儲在一個名為draggingItem的屬性中,並將不透明度設置為 0,具體取決於它是否為 nil。 當 DropDelegate 中的 performDrop 被調用時,我將draggingItem設置回 nil 以使相應的項目再次可見。

有兩種情況下 performDrop 似乎沒有被調用:

  1. 當該項目被 onDrag 然后釋放到位而不移動。

  2. 當項目確實被釋放時,會稍微偏移實際的放置區域。

這導致該項目不再可見,因為draggingItem沒有再次設置為 nil。

有什么想法可以更好地將draggingItem設置回 nil 嗎?

在此處輸入圖像描述

看法:

struct ReorderingTestsView: View {
    
    @State var draggingItem: BookItem?
    @State var items: [BookItem] = [
        BookItem(name: "Harry Potter"),
        BookItem(name: "Lord of the Rings"),
        BookItem(name: "War and Peace"),
        BookItem(name: "Peter Pane")
    ]
    
    var body: some View {
        VStack{
            ScrollView{
                VStack(spacing: 10){
                    ForEach(items){ item in
                        VStack{
                            Text(item.name)
                                .padding(8)
                                .frame(maxWidth: .infinity)
                        }
                        .background(Color.gray)
                        .cornerRadius(8)
                        .opacity(item.id == draggingItem?.id ? 0.01 : 1) // <- HERE
                        .onDrag {
                            draggingItem = item
                            return NSItemProvider(contentsOf: URL(string: "\(item.id)"))!
                        }
                        .onDrop(of: [.item], delegate: DropViewDelegate(currentItem: item, items: $items, draggingItem: $draggingItem))
                    }
                }
                .animation(.default, value: items)
            }
        }
        .padding(.horizontal)
    }
}

DropViewDelegate:

struct DropViewDelegate: DropDelegate {
    
    var currentItem: BookItem
    var items: Binding<[BookItem]>
    var draggingItem: Binding<BookItem?>

    func performDrop(info: DropInfo) -> Bool {
        draggingItem.wrappedValue = nil // <- HERE
        return true
    }
    
    func dropEntered(info: DropInfo) {
        if currentItem.id != draggingItem.wrappedValue?.id {
            let from = items.wrappedValue.firstIndex(of: draggingItem.wrappedValue!)!
            let to = items.wrappedValue.firstIndex(of: currentItem)!
            if items[to].id != draggingItem.wrappedValue?.id {
                items.wrappedValue.move(fromOffsets: IndexSet(integer: from),
                    toOffset: to > from ? to + 1 : to)
            }
        }
    }
    
    func dropUpdated(info: DropInfo) -> DropProposal? {
       return DropProposal(operation: .move)
    }
}

測試項目:

struct BookItem: Identifiable, Equatable {
    var id = UUID()
    var name: String
}

我調查了一個問題 1) 並在https://stackoverflow.com/a/72181964/12299030中提出了解決方案

問題 2) 可以通過自定義覆蓋的項目提供程序和deinit上的操作來解決,因為取消拖動會話時提供程序被破壞。

使用 Xcode 13.4 / iOS 15.5 測試

演示

主要部分:

    // for demo simplicity, a convenient init can be created instead
    class MYItemProvider: NSItemProvider {
        var didEnd: (() -> Void)?
        deinit {
            didEnd?()     // << here !!
        }
    }

// ...

    let provider = MYItemProvider(contentsOf: URL(string: "\(item.id)"))!
    provider.didEnd = {
        DispatchQueue.main.async {
            draggingItem = nil      // << here !!
        }
    }

完整的測試模塊在這里

對於 iOS,您可以將.onDrop添加到全屏視圖並在那里捕獲performDrop

對於 macOS,我找不到 DropDelegate 的任何解決方案。 出於這個原因,您可以使用類似這樣NSApplication.shared.currentEvent?.type == .leftMouseUp

Timer.scheduledTimer(withTimeInterval: 0.2, repeats: true) { timer in
    if (NSApplication.shared.currentEvent?.type == .leftMouseUp) {
       //perform your endDrop action                
       timer.invalidate()
    }
}

當項目為“onDrag”時,未檢測到的對象釋放是由拖動視圖的不透明度設置為 0 引起的。SwiftUI 忽略與不透明度為 0 的視圖的交互。

當您拖動另一個可拖動項目時,將調用該項目的 dropEntered 並進行重新排序。 重新排序后,拖動現在超過了“自身”。 但由於不透明度設置為 0,SwiftUI 會忽略視圖,因此拖動不再位於放置目標上方。 因此,在修飾時,刪除被取消並且 performDrop 沒有被調用。

如果您仍然希望該項目“不可見”,您可以使用非常低的非零值來表示不透明度,例如 0.001,它會起作用。 當使用 0.3 或 0.5 的不透明度時,我發現它看起來相當不錯。

我遇到了同樣的問題,這是我的示例以及如何解決它:

https://github.com/kvyat/DragAndDrop

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM