Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

like image 949
Fedyanint Timofey Avatar asked Feb 07 '20 13:02

Fedyanint Timofey


1 Answers

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"!

enter image description here

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. enter image description here

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 enter image description here enter image description here

like image 73
user3441734 Avatar answered Sep 20 '22 16:09

user3441734