Почему контекстное меню SwiftUI показывает все строки в режиме предварительного просмотра?

У меня сложное представление в строке списка:

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 - это представление с определенным модификатором contextMenu. Но когда я долго нажимаю на изображение, я вижу в предварительном просмотре не только изображение, но и все строки.

Ни для одного элемента нет другого contextMenu.

Как сделать превью только в контексте изображения?

UPD. Вот простой код, иллюстрирующий проблему.


person Fedyanint Timofey    schedule 07.02.2020    source источник
comment
покажите нам FullWidthImageView   -  person user3441734    schedule 07.02.2020
comment
FullWidthImage Просмотр самого изображения (верхняя цена и кнопка сердца)   -  person Fedyanint Timofey    schedule 07.02.2020
comment
это представление, где вы определили contextMenu, не так ли?   -  person user3441734    schedule 07.02.2020
comment
Я создаю суть с иллюстрацией проблемы (на основе ответа @asperi)   -  person Fedyanint Timofey    schedule 09.02.2020
comment
Хорошо, наконец-то я понял, о чем вы говорите :-). К сожалению, это стандартное поведение строки списка. есть некоторое обсуждение в stackoverflow (жесты проходят через все компоненты в строке списка)   -  person user3441734    schedule 10.02.2020
comment
попробуйте использовать ScrollView, если можете. Таким образом можно реализовать даже полную функциональность List (если вам это нужно). см. мой ответ на обновление   -  person user3441734    schedule 10.02.2020


Ответы (2)


Мы понятия не имеем, почему в вашем случае это не работает, пока мы не увидим ваш FullWidthImageView и то, как вы создаете контекстное меню. Ответ Аспери - это рабочий пример, и все сделано правильно! Но действительно ли это объяснило вашу проблему?

Проблема в том, что при применении модификатора .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()
    }
}

и далее наш View

FullWidthImageView().id(model.id)

Теперь все работает так, как мы и ожидали. введите здесь описание изображения

В качестве другого примера, когда "стандартное" состояние / привязка просто не работает, проверьте SwiftUI иерархический выбор со сбоем динамических данных

ОБНОВЛЕНИЕ

В качестве временного обходного пути вы можете имитировать List с помощью 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)
                    }
                }
            }
        }
    }
}

Это не оптимально, но в вашем случае должно работать  введите описание изображения здесь  введите описание изображения здесь

person user3441734    schedule 07.02.2020
comment
Это другой вопрос, но что произойдет, если вы включите .onAppear{..} в один из пунктов контекстного меню, после чего ваш метод .onAppear{...} всегда будет запускаться, даже если вы не входите в контекстное меню. Любое объяснение этому? - person iGhost; 24.02.2021

Вот код (смоделированный, возможно, ваш сценарий), который работает, т.е. для предварительного просмотра контекстного меню отображается только изображение (проверено с 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)

            }
        }
    }
}
person Asperi    schedule 07.02.2020
comment
пожалуйста, проверьте этот gist.github.com/op183/. есть идея, что не так? - person user3441734; 07.02.2020
comment
Аспери, у вас есть идея, почему он не обновляет изображение, пока отображается контекстное меню? - person user3441734; 07.02.2020
comment
Аспери, проверьте мой собственный ответ на вопрос OP и дайте мне знать ... :-) - person user3441734; 07.02.2020
comment
@FedyanintTimofey, проверьте ссылку выше - она ​​ссылается на какой-то файл .js. - person Asperi; 09.02.2020
comment
@asperi, спасибо например, попробовал корректно работать. Но мой код использует List, и проблема в нем: gist.github.com/tfedyanin/dee0691ebb4cadd9< > - person Fedyanint Timofey; 09.02.2020
comment
Да, @FedyanintTimofey, вы правы - List изменяет поведение, я пропустил упомянутый List в вашем вопросе, но неясно, является ли это ошибкой или функцией. В любом случае, стоит отправить отзыв в Apple. Или используйте ScrollView вместо List, где все работает как положено. - person Asperi; 09.02.2020