Кілька аркушів (isPresented :) не працює у SwiftUI


21

У мене є 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 / ...
Andrew

Відповіді:


25

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

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
Це рішення має сенс і може масштабувати, дякую!
turingtest

Спробував цей код за допомогою оператора переключення замість того, якщо ... інше, і з’явилася помилка "Закриття, що містить оператор управління потоком, не може бути використане з конструктором функцій" ViewBuilder "", який був збитковою, тому що це не так, якщо ... ще є контрольний потік?
Аарон Суррейн

Дякую! Це рішення працює
Adelmaer

Ваші SheetView мають один і той же тип: Текст, як щодо іншого типу? Наскільки я бачу, це не працює.
Куанг Ха

@ QuangHà для цього вам потрібно поступити іншим способом. або ви можете скористатися двома чи більше SheetViews як інакший підхід
Rohit Makwana

11

Ви можете вирішити наступний випадок (протестовано з 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)
    }
}

У мене є одна Оповіщення, але множинне Буль, що є помилковим, але колись правдивим (поза тілом), то я хочу, щоб мій сигнал був відомий, який бул є істинним, і показати певний сигнал
Деван

6

Можна також додати аркуш до EmptyView, розміщеного на тлі подання. Це можна зробити кілька разів:

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

3

Ви можете досягти цього, просто згрупувавши кнопку та виклики .sheet разом. Якщо у вас є один провідний і один трейлінг, це так просто. Однак якщо у вас є декілька навігаційних барітемів або в провідній, або в кінцевій, вам потрібно загорнути їх у 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.