如何在macOS的侧边栏中使用SwiftUI实现拖放目标背景效果?

3

我有一个在macOS上作为侧边栏的SwiftUI列表。对于它的项目,我已经添加了dropDesternation修饰符,就像这样:

.dropDestination(for: URL.self) { urls, _ in
      for url in urls {
          //... adding urls to destination
      }
}

return true
} isTargeted: { inDropArea in
      if inDropArea {
          highlightedItem = item
      } else {
          highlightedItem = nil
    }
}
       

默认情况下,如果光标在项目上方,则不会产生任何效果,但我希望获得与在AppKit中使用NSOutlineView相同的效果。以下是Finder中的示例:

Drag and drop in the Finder sidebar

如您所见,我在上面的代码中实现了highlightedItem。我可以使用它来检查一个项目是否被选中并绘制背景:

 .background {
       if item == highlightedItem {
            RoundedRectangle(cornerRadius: 5)
            .fill(Color.blue)
            .frame(maxWidth: .infinity, maxHeight: .infinity)
       }
}

但是看起来不太一样:

own implementation of sidebar drop target

有趣的是,我想要的效果与使用侧边栏列表选择时得到的效果相同,例如:List(selection: $selectedItem) 必须有一种本地方法来做到这一点,这样我就不必虚构它并获得看起来不太正确的东西。

“但那看起来不太一样”,你是指矩形吗? - DialFrost
是的,我想要与第一张截图相同的样式。虽然使用大量自定义代码可能会起作用,但由于在其他地方可以免费获得它,因此可能有一种简单的方法来启用它作为一个下拉目标。 - Daniel
2个回答

4

List元素可以被选择,并在选择时暂时触发似乎非常有效。

例如...

let Bands: Array<String> = [
    "Beatles", "Rolling Stones", "Animals", "Beach Boys", "Doors",
]

struct ContentView: View {
    @State var selection: String? = nil
    @State var dropSelectionCache: String? = nil

    var body: some View {
        VStack {
            Text("Drag text on onto band to trigger highlighting")
            List(Bands, id: \.self, selection: $selection) { band in
                Text(band)
                    .dropDestination(for: String.self) { _, _ in
                        true
                    } isTargeted: { (isTarget: Bool) in
                        if isTarget {
                            dropSelectionCache = selection
                            withAnimation {
                                selection = band
                            }
                        } else {
                            withAnimation {
                                selection = dropSelectionCache
                            }
                        }
                    }
            }
        }
    }
}

这里有一个gif动画演示了Ventura上的代码操作(抱歉录屏有些晃动 - 那是我而不是代码 :-/ )。

低分辨率的拖放操作演示代码运行


不错的技巧。我已经将许多东西绑定到“selection”,所以如果我实际上不想更改选择,我还需要做一些其他的事情,但这很容易。感谢您的时间和回答! - Daniel

0

shufflingb的解决方法很好,但可能会影响性能,我发现了一个更简单的解决方案。

我为每个列表项创建了一个视图,并使用blistRowBackground()作为背景效果,而不仅仅是.background

struct SidebarItemView: View {
    @ObservedObject var item: Item
    @State private var isTargeted = false

    var body: some View {
        NavigationLink(value: item) {
            Label {
                Text(item.title)

            } icon: {
                Image(systemName: "folder")
            }
            .onDrop(of: [.image], isTargeted: $isTargeted, perform: { itemProviders in
            ...
            return true
            })
        }
        .listRowBackground(
            Color.secondary
                .cornerRadius(5)
                .opacity(isTargeted ? 1.0 : 0.0)
                .padding(.horizontal, 10)
        )
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接