【问题标题】:Why SwiftUI context menu show all row view in preview?为什么 SwiftUI 上下文菜单在预览中显示所有行视图?
【发布时间】:2020-05-23 15:43:07
【问题描述】:

我在列表行中有一个复杂的视图:

var body: some View {
        VStack {
            VStack {
                FullWidthImageView(ad)

                HStack {
                    Text("\(self.price) \(self.ad.currency!)")
                            .font(.headline)
                    Spacer()
                    SwiftUI.Image(systemName: "heart")
                }
                        .padding([.top, .leading, .trailing], 10.0)

FullWidthImageView 是定义了 contexMenu 修饰符的视图。 但是当我长按一个图像时,我看到的不是唯一的预览图像,而是所有行视图。

任何元素上都没有其他 contextMenu。

如何在仅包含图像的上下文中进行预览?

UPD。 Here 是一个说明问题的简单代码

【问题讨论】:

  • 向我们展示 FullWidthImageView
  • FullWidthImage查看其图像本身(价格上限和心形按钮)
  • 它是视图,您在其中定义了 contextMenu,不是吗?
  • 我创建gist 并附有问题说明(基于@asperi 答案)
  • 好的,我终于明白了,你在说什么:-)。不幸的是,这是列表行标准行为。在 stackoverflow 上有一些讨论(手势通过列表行中的所有组件)

标签: ios swiftui contextmenu swiftui-list


【解决方案1】:

我们不知道为什么在您的情况下它不起作用,直到我们看到您的 FullWidthImageView 以及您如何构建上下文菜单。 Asperi 的答案是工作示例,并且做得正确! 但这真的解释了你的麻烦吗?

问题在于,在仅将 .contextMenu 修饰符应用于视图的某些部分(如您的示例中)时,我们必须小心。

让我们看一些例子。

import SwiftUI

struct FullWidthImageView: View {
    @ObservedObject var model = modelStore
    var body: some View {
        VStack {
            Image(systemName: model.toggle ? "pencil.and.outline" : "trash")
                .resizable()
                .aspectRatio(contentMode: .fit)
                .frame(width: 200)
        }.contextMenu(ContextMenu {
            Button(action: {
                self.model.toggle.toggle()
            }) {
                HStack {
                    Text("toggle image to?")
                    Image(systemName: model.toggle ? "trash" : "pencil.and.outline")
                }
            }
            Button("No") {}
        })
    }
}

class Model:ObservableObject {
    @Published var toggle = false
}

let modelStore = Model()

struct ContentView: View {
    @ObservedObject var model = modelStore
    var body: some View {
        VStack {
            FullWidthImageView()
            Text("Long press the image to change it").bold()
        }
    }
}
struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

在运行时,修改后的“上下文菜单”视图似乎是“静态的”

是的,在长按时,您会看到垃圾图像,即使在您关闭上下文视图时它已正确更新。 每次长按都只会看到垃圾!

如何使其动态化?我需要图像与我的“主视图! 这里有.id 修饰符。让我们看看有什么不同!

首先我们必须更新我们的模型

class Model:ObservableObject {
    @Published var toggle = false
    var id: UUID {
        UUID()
    }
}

接下来是我们的视图

FullWidthImageView().id(model.id)

现在它按我们的预期工作了。

再举一个例子,“标准”状态/绑定根本不起作用检查SwiftUI hierarchical Picker with dynamic data crashes

更新

作为一种临时解决方法,您可以通过 ScrollView 模仿 List

import SwiftUI

struct Row: View {
    let i:Int
    var body: some View {
        VStack {
            Image(systemName: "trash")
                .resizable()
                .aspectRatio(contentMode: .fit)
                .frame(width: 200)
                .contextMenu(ContextMenu {
                    Button("A") {}
                    Button("B") {}
                })
            Text("I don’t want to show in preview because I don’t have context menu modifire").bold()
        }.padding()
    }
}

struct ContentView: View {
    var body: some View {
        VStack {
            ScrollView {
                ForEach(0 ..< 20) { (i) in
                    VStack {
                        Divider()
                        Row(i: i)
                    }
                }
            }
        }
    }
}

这不是最佳的,但在你的情况下它应该可以工作

【讨论】:

  • 这是另一个问题,但是如果您在上下文菜单项之一中包含.onAppear{..} 会发生什么情况,之后,即使您不输入,您的.onAppear{...} 方法也会被触发在上下文菜单中。对此有何解释?
【解决方案2】:

这是一个有效的代码(模拟可能的场景),即。仅显示上下文菜单预览的图像(使用 Xcode 11.3+ 测试)。

struct FullWidthImageView: View {
    var body: some View {
        Image("auto")
            .resizable()
            .aspectRatio(contentMode: .fit)
            .frame(width: 200)
            .contextMenu(ContextMenu() {
                Button("Ok") {}
            })
    }
}

struct TestContextMenu: View {
    var body: some View {
        VStack {
            VStack {
                FullWidthImageView()

                HStack {
                    Text("100 $")
                        .font(.headline)
                    Spacer()
                    Image(systemName: "heart")
                }
                .padding([.top, .leading, .trailing], 10.0)

            }
        }
    }
}

【讨论】:

  • 请检查一下gist.github.com/op183/…你知道出了什么问题吗?
  • Asperi,你知道为什么它在显示上下文菜单时不“更新”图像吗?
  • Asperi,检查我自己对 OP 问题的回答,然后告诉我... :-)
  • @FedyanintTimofey,请检查您上面的链接 - 它引用了一些 .js 文件。
  • @asperi ,例如谢谢你,我试过它可以正常工作。但是我的代码使用 List 并且问题出在其中:gist.github.com/tfedyanin/d0691ebbcaddb2b4bef943d35e8ee202
【解决方案3】:

它隐藏在此处的回复中,但关键发现​​是List 正在改变.contextMenu 的行为——它创建了与菜单一起弹出的“块”,而不是将菜单附加到指定的元素。将List 换成ScrollView 可以解决此问题。

【讨论】:

    猜你喜欢
    • 2020-11-17
    • 2022-12-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-12-16
    • 2022-08-17
    • 1970-01-01
    相关资源
    最近更新 更多