简体   繁体   中英

Why SwiftUI context menu show all row view in preview?

I have a complex view in List row:

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)

Where FullWidthImageView is view with defined contexMenu modifier. But when I long-press on an image I see not the only image in preview, but all row view.

There is no other contextMenu on any element.

How to make a preview in context with image only?

UPD. Here is a simple code illustrating the problem

We don't have any idea why in your case it doesn't work, until we see your FullWidthImageView and how you construct the context menu. Asperi's answer is working example, and it is correctly done! But did it really explain your trouble?

The trouble is that while applying .contextMenu modifier to only some part of your View (as in your example) we have to be careful.

Let see some example.

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()
    }
}

while running, the "context menu" modified View seems to be "static" !

在此处输入图片说明

Yes, on long press, you see the trash image, even though it is updated properly while you dismiss the context view. On every long press you see trash only!

How to make it dynamic? I need that the image will be the same, as on my "main View! Here we have .id modifier . Let see the difference!

First we have to update our model

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

and next our View

FullWidthImageView().id(model.id)

Now it works as we expected. 在此处输入图片说明

For another example, where "standard" state / binding simply doesn't work check SwiftUI hierarchical Picker with dynamic data crashes

UPDATE

As a temporary workaround you can mimic List by ScrollView

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

It is not optimal, but in your case it should work在此处输入图片说明 在此处输入图片说明

Here is a code (simulated possible your scenario) that works, ie. only image is shown for context menu preview (tested with 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)

            }
        }
    }
}

It's buried in the replies here, but the key discovery is that List is changing the behavior of .contextMenu -- it creates "blocks" that pop up with the menu instead of attaching the menu to the element specified. Switching out List for ScrollView fixes the issue.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM