0

Problem

enter image description here

I was expecting the existing toolbar to disappear whenever the next view is pushed.

However, it behaves differently than I expected.

When the next view is pushed, it comes in with the existing toolbar remaining.

Why is this happening?

p.s. Our app requires the tabbar to always be exposed. So I can't use navigationview inside tabview.

My code

CustomNavigation

import SwiftUI
import Foundation

public enum GPToolbarItem {
  case logo(_ didTap: (() -> Void)? = nil)
  case magnifyingGlass(_ didTap: (() -> Void)? = nil)
  case chevronLeft(_ didTap: (() -> Void)? = nil)
  case heart(_ didTap: (() -> Void)? = nil)
  case text(_ didTap: (() -> Void)? = nil)
}

extension GPToolbarItem: Identifiable {
  public var id: UUID { .init() }
}

public extension View {
  func gpNavigationTitle(_ title: Text) -> some View {
    return modifier(GPNavigationTitleModifier(title: title))
  }

  func gpToolbarItem(leftItems: [GPToolbarItem], rightItems: [GPToolbarItem]) -> some View {
    return modifier(GPToolbarItemModifier(leftItems: leftItems, rightItems: rightItems))
  }
}
struct GPToolbarItemModifier: ViewModifier {
  private let leftItems: [GPToolbarItem]
  private let rightItems: [GPToolbarItem]
  
  init(leftItems: [GPToolbarItem], rightItems: [GPToolbarItem]) {
    self.leftItems = leftItems
    self.rightItems = rightItems
  }
  
  func body(content: Content) -> some View {
    content
      .navigationBarBackButtonHidden(true)
      .toolbar {
        ToolbarItemGroup(placement: .navigationBarLeading) {
          ItemBuilder(items: self.leftItems)
        }
        ToolbarItemGroup(placement: .navigationBarTrailing) {
          ItemBuilder(items: self.rightItems)
        }
      }
  }
  
  @ViewBuilder
  private func ItemBuilder(items: [GPToolbarItem]) -> some View {
    ForEach(items) {
      switch $0 {
      case let .logo(tapGesture):
        Button("logo") {
          tapGesture?()
        }
      case let .magnifyingGlass(tapGesture):
        Button("magnifyingGlass") {
          tapGesture?()
        }
      case let .chevronLeft(tapGesture):
        Button("chevronLeft") {
          tapGesture?()
        }
      case let .heart(tapGesture):
        Button("heart") {
          tapGesture?()
        }
      case let .text(tapGesture):
        Button("text") {
          tapGesture?()
        }
      }
    }
  }
}
struct GPNavigationTitleModifier: ViewModifier {
  private let title: Text
  
  init(title: Text) { self.title = title }
  
  func body(content: Content) -> some View {
    content
      .navigationBarBackButtonHidden(true)
      .navigationBarTitleDisplayMode(.inline)
      .navigationTitle(self.title)
  }
}

Usage

import SwiftUI

@main
struct NavigationAndTabApp: App {
    var body: some Scene {
        WindowGroup {
          NavigationView {
            TabView {
              GPNavigationPreview()
                .tabItem {
                  Image(systemName: "house")
                  Text("home")
                }
              SwiftUIView()
                .tabItem {
                  Image(systemName: "house")
                  Text("home")
                }
            }
          }
        }
    }
}

struct GPNavigationPreview: View {
    var body: some View {
      NavigationView {
        NavigationLink(destination: GPNavigationPreview2()) {
          Text("GPNavigationPreview")
        }
      }
      .gpNavigationTitle(.init("GPNavigationPreview"))
      .gpToolbarItem(leftItems: [.logo()], rightItems: [.magnifyingGlass()])
    }
}

struct GPNavigationPreview2: View {
    var body: some View {
      NavigationLink(destination: GPNavigationPreview3()) {
        Text("GPNavigationPreview2")
      }
      .gpToolbarItem(leftItems: [.chevronLeft()], rightItems: [.heart()])
    }
}

struct GPNavigationPreview3: View {
    var body: some View {
      Text("GPNavigationPreview3")
    }
}

Thanks in advance for your answer.

wimes
  • 23
  • 4
  • Hello! Please have a look on my answer there https://stackoverflow.com/a/73352327/4981515 . It should help. – Alexander Khitev May 15 '23 at 16:32
  • @AlexanderKhitev Thanks for your answer. Unfortunately, our app requires the tabbar to always be exposed. So i can't use navigationview inside tabview. – wimes May 16 '23 at 00:23
  • Can you attach the code for the parent View that calls your NavigaionView? It seems that you may need to modify the code in the parent view. – Cheolhyun May 16 '23 at 00:58
  • @Cheolhyun Thanks for your advice. I think it's a problem with TabView. I know the problem, but I haven't been able to find a solution yet. I've updated it with that code. – wimes May 16 '23 at 12:06

1 Answers1

0

This has nothing to do with TabView.

The reason why the NavigationToolbar Items in the first View don't disappear in the second View is because you declared the .toolbar in the NavigationView.

Moving where you declare the .toolbar should fix it, like this

struct GPNavigationPreview: View {
    var body: some View {
        NavigationView {
            NavigationLink(destination: GPNavigationPreview2()) {
                Text("GPNavigationPreview")
            }
            .gpToolbarItem(leftItems: [.logo()], rightItems: [.magnifyingGlass()])  // <--  2. to here
        }
        .gpNavigationTitle(.init("GPNavigationPreview"))
        // .gpToolbarItem(leftItems: [.logo()], rightItems: [.magnifyingGlass()])  // <--  1. move
    }
}
Cheolhyun
  • 169
  • 1
  • 7
  • This is helpful for me. Also, in debugging my code, GPNavigationPreview I was using NavigationView in . When I remove that NavigationView, it works perfectly. Thank you for the answer. – wimes May 17 '23 at 00:06