如何使用 SwiftUI 在 macOS 上获得侧边栏中的放置目标背景效果?

问题描述 投票:0回答:2

我有一个 SwiftUI 列表,它是 macOS 上的侧边栏。对于其项目,我添加了 dropDestination 修饰符,如下所示:

.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)

必须有一种本地方法来做到这一点,这样我就不必伪造它并得到看起来不太正确的东西。

macos swiftui drag-and-drop sidebar
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 上运行的代码(对屏幕录制的轻微抖动表示歉意 - 这是我的,而不是代码:-/)

Low res drag and drop showing code in operation


1
投票

shufflingb 的解决方法很好,但可能会对性能产生副作用,我找到了一个更简单的解决方案。

我为每个列表项创建了一个视图,并使用

.listRowBackground()
作为背景效果,而不仅仅是
.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)
        )
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.