Закрытие представления с помощью статической панели навигации

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

Проблема, с которой я сейчас сталкиваюсь, заключается в том, чтобы отклонить дочернее представление, когда я ушел от родительского представления. Я могу обновить кнопку со значка меню до значка назад, но действие кнопки не запускается. Я искал в Интернете, чтобы узнать, сделал ли кто-нибудь что-то подобное, но ему не повезло, я не уверен, что то, чего я пытаюсь достичь, возможно, и правильно ли я иду в этом направлении. Есть ли способ вызвать self.presentationMode.wrappedValue.dismiss() из дочерних представлений, даже если заголовок инициализирован в корневом представлении? Любая помощь приветствуется, вот что у меня есть:

Корневой вид (View1):

struct View1: View {
    @State var showMenuButton: Bool = false
    var body: some View {
        VStack {
            CustomNavigationView(showMenuButton: self.showMenuButton)

            NavigationView {
                NavigationLink(destination: View2()) {
                    Text("View 2")
                }
                .navigationBarTitle("")
                .navigationBarHidden(true)
                .onDisappear(){
                    self.showMenuButton = false
                }
                .onAppear() {
                    self.showMenuButton = true
                }
            }
        }
    }
}

Детский вид корневого представления (View2):

struct View2: View {
    var body: some View {
        VStack{
            Text("This is View 2")
            .navigationBarTitle("")
            .navigationBarHidden(true)
            NavigationLink(destination: View3()) {
                Text("View 3")
            }
        }
    }
}

Детский вид представления 2 (View3):

struct View3: View {
    var body: some View {
        VStack{
            Text("This is View 3")
            .navigationBarTitle("")
            .navigationBarHidden(true)
        }
    }
}

Пользовательский вид навигации:

struct CustomNavigationView: View {
    @Environment(\.presentationMode) var presentationMode: Binding<PresentationMode>
    var showMenuButton = false
    var body: some View {
        VStack {
            HStack {
                if showMenuButton {
                    Button(action: {
                        //Do Something
                    }) {
                        Image(systemName: "line.horizontal.3")
                        .foregroundColor(.black)
                    }
                } else {
                    Button(action: { self.presentationMode.wrappedValue.dismiss()}) {
                        Image(systemName: "arrow.left")
                        .foregroundColor(.black)
                    }
                }
                Text("Sometext")            
            }
        }
    }
}

person Mehul Mandalia    schedule 11.05.2020    source источник


Ответы (1)


Объект среды «presentationMode», который вы использовали в первом представлении, не может отклонять отправленные вами представления. У каждой точки зрения, которую нужно отвергнуть, должны быть свои объекты. Объект внутри первого представления не принадлежит никаким другим перемещаемым представлениям. Итак, вам нужно создать модель представления для управления этой задачей.

Вот пример кода. Надеюсь, это поможет вам решить вашу проблему.

class NavigationObserver: ObservableObject {
    private var views: [Int:Binding<PresentationMode>] = [:]
    private var current: Int = 0

    func popView() {
       guard let view = views[current] else {
          return
       }
       view.wrappedValue.dismiss()
       views[current] = nil
       current -= 1
     }

    func pushView(id: Int, newView: Binding<PresentationMode>) {
       guard views[id] == nil else {
          return
       }
       current += 1
       views[id] = newView
     }
   }

struct ContentView: View {
@State var showMenuButton: Bool = false
@ObservedObject var observer = NavigationObserver()
var body: some View {
    VStack {
        CustomNavigationView(observer: self.observer, showMenuButton: self.showMenuButton)

        NavigationView {
            NavigationLink(destination: View2(observer: self.observer)) {
                Text("View 2")
            }
            .navigationBarTitle("")
            .navigationBarHidden(true)
            .onDisappear(){
                self.showMenuButton = false
            }
            .onAppear() {
                self.showMenuButton = true
            }
        }
    }
}}
struct View2: View {
@Environment(\.presentationMode) var presentationMode
@ObservedObject var observer: NavigationObserver
var body: some View {
    VStack{
        Text("This is View 2")
        .navigationBarTitle("")
        .navigationBarHidden(true)
        NavigationLink(destination: View3(observer: self.observer)) {
            Text("View 3")
        }
    }.onAppear {
        self.observer.pushView(id: 1, newView: self.presentationMode)
    }
}}

struct View3: View {
@Environment(\.presentationMode) var presentationMode
@ObservedObject var observer: NavigationObserver
var body: some View {
    VStack{
        Text("This is View 3")
        .navigationBarTitle("")
        .navigationBarHidden(true)
    }.onAppear
        {
            self.observer.pushView(id: 2, newView: self.presentationMode)
        }
}
}

struct CustomNavigationView: View {
@ObservedObject var observer: NavigationObserver
var showMenuButton = false
var body: some View {
    VStack {
        HStack {
            if showMenuButton {
                Button(action: {
                    //Do Something
                }) {
                    Image(systemName: "line.horizontal.3")
                    .foregroundColor(.black)
                }
            } else {
                Button(action: {
                    self.observer.popView()
                }) {
                    Image(systemName: "arrow.left")
                    .foregroundColor(.black)
                }
            }
            Text("Sometext")
        }
    }
}
}

Спасибо, X_X

person Dscyre Scotti    schedule 12.05.2020
comment
Идеально! Работает именно так, как я себе это представлял. Я знал, что объект presentationMode не сможет отклонить дочерние представления, и именно здесь я ударился о кирпичную стену. Насколько я понимаю, вы создаете словарь с идентификатором для каждого представления в истории навигации в качестве ключа и индивидуальным режимом представления представления в качестве значения. Затем отклоните его и удалите из словаря. Большое спасибо! - person Mehul Mandalia; 12.05.2020