SwiftUI - Как закрыть представление листа, одновременно отклоняя это представление - PullRequest
3 голосов
/ 20 февраля 2020

Я хочу добиться этой функции. Как, например, представление «Взгляд вверх» от Apple.

Моя цель состоит в том, чтобы при просмотре листа pu sh другой вид с помощью навигации, пользователь мог нажать кнопку элемента навигации, чтобы закрыть вид листа. Например, это ниже gif.

enter image description here

Я пытаюсь выполнить эту функцию.

Я обнаружил проблему, когда пользователь нажимает кнопка «Готово». Приложение не закрывает вид листа. Это только выдвигает представление в родительское представление. Например, это ниже gif.

enter image description here

Это мой код.

import SwiftUI

struct ContentView: View {
    @State var isShowSheet = false
    var body: some View {
        Button(action: {
            self.isShowSheet.toggle()
        }) {
            Text("Tap to show the sheet")
        }.sheet(isPresented: $isShowSheet) {
            NavView()
        }
    }
}

struct NavView: View {
    var body: some View {
        NavigationView {
            NavigationLink(destination: NavSubView()) {
                Text("Enter Sub View")
            }
        } .navigationViewStyle(StackNavigationViewStyle())
    }
}

struct NavSubView: View {
    @Environment(\.presentationMode) var presentationMode

    var body: some View {
        Text("Hello")
        .navigationBarItems(trailing:
            Button(action: {
                self.presentationMode.wrappedValue.dismiss()
            }){
                Text("Done")
            }
        )
    }
}

Как я достиг этой функции? :) Пожалуйста, помогите мне, спасибо. :)

Ответы [ 2 ]

2 голосов
/ 20 февраля 2020

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

Здесь возможен подход (протестировано с Xcode 11.2 / iOS 13.2)

1) Определите ключ среды для сохранения состояния листа

struct ShowingSheetKey: EnvironmentKey {
    static let defaultValue: Binding<Bool>? = nil
}

extension EnvironmentValues {
    var showingSheet: Binding<Bool>? {
        get { self[ShowingSheetKey.self] }
        set { self[ShowingSheetKey.self] = newValue }
    }
}

2) Установите это значение среды на root содержимого листа, поэтому он будет доступен в любом подпредставлении, когда объявлено

    }.sheet(isPresented: $isShowSheet) {
        NavView()
           .environment(\.showingSheet, self.$isShowSheet)
    }

3) Объявить и использовать значение среды только в подпредставлении, где оно будет использоваться

struct NavSubView: View {
    @Environment(\.showingSheet) var showingSheet

    var body: some View {
        Text("Hello")
        .navigationBarItems(trailing:
            Button("Done") {
                self.showingSheet?.wrappedValue = false
            }
        )
    }
}
2 голосов
/ 20 февраля 2020

Я никогда не пробовал SwiftUI, но пришел из UIKit + RxSwift, так что я знаю, как работает связывание. Я прочитал довольно много примеров кодов из учебного пособия по SwiftUI, и способ, которым вы отклоняете модальный режим, действительно верен, но, очевидно, не для стека навигации. вар. Возможно, это не лучшее решение, но оно сработало!

Итак, у вас есть $isShowSheet в вашем ContentView. Передайте этот объект в структуру NavView, объявив переменную в этом NavView.

ContentView

    .....

    }.sheet(isPresented: $isShowSheet) {
        NavView(isShowSheet: self.$isShowSheet)
    }

NavView

struct NavView: View {
    @Binding var isShowSheet: Bool

    var body: some View {
        NavigationView {
            NavigationLink(destination: NavSubView(isShowSheet: self.$isShowSheet)) {
                Text("Enter Sub View")
            }
        } .navigationViewStyle(StackNavigationViewStyle())
    }
}

и, наконец, сделайте то же самое с вашим подвидом.

NavSubView

struct NavSubView: View {
    @Environment(\.presentationMode) var presentationMode

    @Binding var isShowSheet: Bool

    var body: some View {
        Text("Hello")
        .navigationBarItems(trailing:
            Button(action: {
                //self.presentationMode.projectedValue.wrappedValue.dismiss()
                self.isShowSheet = false
            }){
                Text("Done")
            }
        )
    }
}

Теперь, как вы видите, вам просто нужно отправьте новый сигнал этому isShowSheet переплету - false.

self.isShowSheet = false

Вуаля!

enter image description here

...