Несколько листов (isPresented :) не работает в SwiftUI


22

У меня есть этот ContentView с двумя различными модальными представлениями, поэтому я использую sheet(isPresented:)оба, но, как кажется, представлен только последний. Как я мог решить эту проблему? Или невозможно использовать несколько листов для просмотра в SwiftUI?

struct ContentView: View {

    @State private var firstIsPresented = false
    @State private var secondIsPresented = false

    var body: some View {

        NavigationView {
            VStack(spacing: 20) {
                Button("First modal view") {
                    self.firstIsPresented.toggle()
                }
                Button ("Second modal view") {
                    self.secondIsPresented.toggle()
                }
            }
            .navigationBarTitle(Text("Multiple modal view problem"), displayMode: .inline)
            .sheet(isPresented: $firstIsPresented) {
                    Text("First modal view")
            }
            .sheet(isPresented: $secondIsPresented) {
                    Text("Only the second modal view works!")
            }
        }
    }
}

Приведенный выше код компилируется без предупреждений (Xcode 11.2.1).


Вы можете иметь только один лист. Это решение показывает, как получать различные оповещения, которые похожи на вашу ситуацию и, вероятно, могут быть легко перенаправлены stackoverflow.com/questions/58737767/…
Эндрю

Ответы:


27

Пожалуйста, попробуйте ниже код

enum ActiveSheet {
   case first, second
}

struct ContentView: View {

    @State private var showSheet = false
    @State private var activeSheet: ActiveSheet = .first

    var body: some View {

        NavigationView {
            VStack(spacing: 20) {
                Button("First modal view") {
                    self.showSheet = true
                    self.activeSheet = .first
                }
                Button ("Second modal view") {
                    self.showSheet = true
                    self.activeSheet = .second
                }
            }
            .navigationBarTitle(Text("Multiple modal view problem"), displayMode: .inline)
            .sheet(isPresented: $showSheet) {
                if self.activeSheet == .first {
                    Text("First modal view")
                }
                else {
                    Text("Only the second modal view works!")
                }
            }
        }
    }
}

1
Это решение имеет смысл и может масштабироваться, спасибо!
тестирование turing

Попробовал этот код с оператором switch вместо if ... else и получил ошибку «Замыкание, содержащее оператор потока управления, нельзя использовать со сборщиком функции 'ViewBuilder'", что было сбивающим с толку, потому что нет, если ... else это поток управления?
Аарон Сюррейн

Спасибо! Это решение работает
Адельмаер

Ваши SheetViews имеют один и тот же тип: текст, как насчет другого типа? Насколько я вижу, это не работает.
Куанг Ха

@ QuangHà для этого вам нужно сделать по-другому. или вы можете использовать два или более SheetViews как другой подход
Рохит Маквана

12

Ваш случай может быть решен с помощью следующего (протестировано с Xcode 11.2)

var body: some View {

    NavigationView {
        VStack(spacing: 20) {
            Button("First modal view") {
                self.firstIsPresented.toggle()
            }
            .sheet(isPresented: $firstIsPresented) {
                    Text("First modal view")
            }
            Button ("Second modal view") {
                self.secondIsPresented.toggle()
            }
            .sheet(isPresented: $secondIsPresented) {
                    Text("Only the second modal view works!")
            }
        }
        .navigationBarTitle(Text("Multiple modal view problem"), displayMode: .inline)
    }
}

У меня есть одно предупреждение, но несколько Bool, которое является ложным, но когда-то истинным (вне тела), тогда я хочу, чтобы мое предупреждение узнало, какой Bool является истинным, и показало определенное предупреждение
Деван

6

Можно также добавить лист в EmptyView, размещенный на фоне представления. Это можно сделать несколько раз:

  .background(EmptyView()
        .sheet(isPresented: isPresented, content: content))

3

Это можно сделать, просто сгруппировав вызовы кнопки и таблицы. Если у вас есть один ведущий и один трейлинг, это так просто. Однако, если у вас есть несколько навигационных элементов в начале или конце, вам нужно обернуть их в HStack, а также обернуть каждую кнопку своим вызовом листа в VStack.

Вот пример двух конечных кнопок:

            trailing:
            HStack {
                VStack {
                    Button(
                        action: {
                            self.showOne.toggle()
                    }
                    ) {
                        Image(systemName: "camera")
                    }
                    .sheet(isPresented: self.$showOne) {
                        OneView().environment(\.managedObjectContext, self.managedObjectContext)
                    }
                }//showOne vstack

                VStack {
                    Button(
                        action: {
                            self.showTwo.toggle()
                    }
                    ) {
                        Image(systemName: "film")
                    }
                    .sheet(isPresented: self.$showTwo) {
                        TwoView().environment(\.managedObjectContext, self.managedObjectContext)
                    }
                }//show two vstack
            }//nav bar button hstack

1

В дополнение к ответу Рохита Макваны , я нашел способ извлечь содержимое листа в функцию, потому что компилятору было сложно проверять мой гигантский тип View.

extension YourView {
    enum Sheet {
        case a, b
    }

    @ViewBuilder func sheetContent() -> some View {
        if activeSheet == .a {
            A()
        } else if activeSheet == .b {
            B()
        }
    }
}

Вы можете использовать это так:

.sheet(isPresented: $isSheetPresented, content: sheetContent)

Это делает код чище, а также снимает стресс вашего компилятора.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.