我在视图上使用.contextMenu
with .onDrag
,这似乎非常棘手:
通过设置为 true,背景颜色变为灰色dragging
。这是由.onDrag
打开上下文菜单时已经发生的情况触发的(有点早但还可以)。当我使用按钮关闭菜单时,我可以设置dragging
为 false。当我使用拖动时,取消初始化dragging
时状态会更改回 false 。ItemProvider
到目前为止,一切都很好。
问题
当我点击上下文菜单外部将其关闭时,我似乎无法将dragging
状态设置回 false。添加.onDisappear
到Button
菜单中不起作用。
我在这里做错了什么?有什么方法可以在上下文菜单关闭时收到通知,或者在拖动实际开始时发生状态更改dragging
(以便在打开上下文菜单时背景不会立即变为灰色)?
代码如下视频。
struct ContentView: View {
@State var dragging = false
var body: some View {
ZStack {
Rectangle()
.foregroundColor(.blue)
.frame(width: 100, height: 100)
.onDrag {
dragging = true
let provider = ItemProvider(contentsOf: URL(string: "Test")!)!
provider.didEnd = {
DispatchQueue.main.async {
dragging = false
}
}
print("init ItemProvider")
return provider
}
.contextMenu {
Button("Close Menu") {
dragging = false
}
}
}
.frame(maxWidth: .infinity, maxHeight: .infinity)
.background(dragging ? Color.gray : Color.white)
}
}
class ItemProvider: NSItemProvider {
var didEnd: (() -> Void)?
deinit {
print("deinit ItemProvider")
didEnd?()
}
}
Run Code Online (Sandbox Code Playgroud)
编辑(2022 年 12 月):代码似乎可以在 iOS 16.2 中运行。对于早期的 iOS 版本,我仍然没有找到一个好的解决方案。
既然你提到了 UIKit,.contextMenu
那就是UIContextMenuInteraction
您可以向 SwiftUI 视图添加UIContextMenuInteraction
并有权UIContextMenuInteractionDelegate
识别菜单何时关闭。
SwiftUI View > ViewModifier > UIViewRepresentable > Coordinator/UIContextMenuInteractionDelegate
struct CustomContextMenuView: View {
@State var dragging = false
var body: some View {
ZStack {
Rectangle()
.foregroundColor(.blue)
.frame(width: 100, height: 100)
.onDrag {
dragging = true
let provider = ItemProvider(contentsOf: URL(string: "Test")!)!
provider.didEnd = {
DispatchQueue.main.async {
dragging = false
}
}
print("init ItemProvider")
return provider
}
//Use custom context menu and add actions as [UIAction]
.contextMenu(actions: [
UIAction(title: "Close Menu", handler: { a in
print("Close Menu action")
dragging = false
})
], willEnd: {
//Called when the menu is dismissed
print("willEnd/onDismiss")
dragging = false
}, willDisplay: {
//Called when the menu appears
print("willDisplay/onAppear")
})
}
.frame(maxWidth: .infinity, maxHeight: .infinity)
.background(dragging ? Color.gray : Color.white)
}
}
Run Code Online (Sandbox Code Playgroud)
.swift
可以通过将以下代码粘贴到文件中并像上面的示例一样使用它来实现菜单。
extension View {
func contextMenu(actions: [UIAction], willEnd: (() -> Void)? = nil, willDisplay: (() -> Void)? = nil) -> some View {
modifier(ContextMenuViewModifier(actions: actions, willEnd: willEnd, willDisplay: willDisplay))
}
}
struct ContextMenuViewModifier: ViewModifier {
let actions: [UIAction]
let willEnd: (() -> Void)?
let willDisplay: (() -> Void)?
func body(content: Content) -> some View {
Interaction_UI(view: {content}, actions: actions, willEnd: willEnd, willDisplay: willDisplay)
.fixedSize()
}
}
struct Interaction_UI<Content2: View>: UIViewRepresentable{
typealias UIViewControllerType = UIView
@ViewBuilder var view: Content2
let actions: [UIAction]
let willEnd: (() -> Void)?
let willDisplay: (() -> Void)?
func makeCoordinator() -> Coordinator {
return Coordinator(parent: self)
}
func makeUIView(context: Context) -> some UIView {
let v = UIHostingController(rootView: view).view!
context.coordinator.contextMenu = UIContextMenuInteraction(delegate: context.coordinator)
v.addInteraction(context.coordinator.contextMenu!)
return v
}
func updateUIView(_ uiView: UIViewType, context: Context) {
}
class Coordinator: NSObject, UIContextMenuInteractionDelegate{
var contextMenu: UIContextMenuInteraction!
let parent: Interaction_UI
init(parent: Interaction_UI) {
self.parent = parent
}
func contextMenuInteraction(_ interaction: UIContextMenuInteraction, configurationForMenuAtLocation location: CGPoint) -> UIContextMenuConfiguration? {
UIContextMenuConfiguration(identifier: nil, previewProvider: nil, actionProvider: { [self]
suggestedActions in
return UIMenu(title: "", children: parent.actions)
})
}
func contextMenuInteraction(_ interaction: UIContextMenuInteraction, willDisplayMenuFor configuration: UIContextMenuConfiguration, animator: UIContextMenuInteractionAnimating?) {
print(#function)
parent.willDisplay?()
}
func contextMenuInteraction(_ interaction: UIContextMenuInteraction, willEndFor configuration: UIContextMenuConfiguration, animator: UIContextMenuInteractionAnimating?) {
print(#function)
parent.willEnd?()
}
}
}
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
1085 次 |
最近记录: |