Reading time: 1 min

This recipe shows how to update navigation bar when the content underneath it scrolls.

The end result looks like this:

preview

The recipe relies on the ObservableScrollView from this recipe, because it can track its scroll offset. After that, it becomes trivial to check if the user has scrolled past a certain point and update the navigation bar.

The scrollToTop functionality relies on a method from this recipe.

Here's the full code:

struct UpdateNavigationBarOnScroll: View {
  @State var scrollOffset: CGFloat = .zero
  @State var scrollToTop = false

  private var hasScrolled: Bool {
    scrollOffset > 0
  }

  var body: some View {
    NavigationView {
      scrollView
        .navigationBarTitle(hasScrolled ? "Thanks!" : "Scroll, please!",
                            displayMode: .inline)
        .navigationBarItems(trailing: navBarButton)
    }
  }

  @ViewBuilder private var scrollView: some View {
    ObservableScrollView(scrollOffset: $scrollOffset) { proxy in
      LazyVStack {
        ForEach(0..<100) { index in
          Text("Row \(index)")
            .id(index)
        }
      }
      .onChange(of: scrollToTop) { newValue in
        if newValue {
          scrollToTop = false
          withAnimation {
            proxy.scrollTo(0, anchor: .top)
          }
        }
      }
    }
  }

  @ViewBuilder private var navBarButton: some View {
    if hasScrolled {
      Button("To top") {
        scrollToTop = true
      }
    } else {
      EmptyView()
    }
  }
}

Next Post Previous Post