Trying to make header pinned between below the navigation bar using safeAreaInset modifier. When I start swiping navigation bar down, the safeAreaInset content remains on the same position although navigation title and List content moves down.

Is it possible to make the header scrolling along with the navigation bar?

struct ContentView: View {
  
  var body: some View {
    NavigationStack {
      List([0, 1, 2, 3], id: .self) {
        Text("($0)")
      }
      .navigationTitle("Navigation Title")
      .safeAreaInset(edge: .top, alignment: .leading) {
        Text("Safe Area Header")
          .foregroundStyle(Color.blue)
          .font(.title)
          .padding()
      }
    }
  }
}

enter image description here

I didn’t found the out of the box SwiftUI solution. But I was able to fix this by observing the List offset and then calculating the correct header inset (firstRowInset - safeAreaTopInset).

struct ContentView: View {
  
  @State private var scrollOffset = 0.0
  
  var body: some View {
    NavigationStack {
      ItemsList(items: [0, 1, 2, 3])
        .safeAreaInset(edge: .top, alignment: .leading) {
          Text("Safe Area Header")
            .foregroundStyle(Color.blue)
            .font(.title)
            .padding()
            .offset(y: max(scrollOffset, 0.0))
        }
        .navigationTitle("Navigation Title")
        .onPreferenceChange(
          ScrollOffsetPreferenceKey.self,
          perform: { scrollOffset = $0 }
        )
    }
  }
  
  private struct ScrollOffsetPreferenceKey: PreferenceKey {
    static var defaultValue: CGFloat = 0
    
    static func reduce(
      value: inout CGFloat,
      nextValue: () -> CGFloat
    ) {
      value += nextValue()
    }
  }
  
  private struct ItemsList: View {
    let items: [Int]
    
    var body: some View {
      GeometryReader { geometry in
        List(items, id: .self) { item in
          Row(value: item)
            .background {
              if item == items.first {
                ScrollOffsetPreferenceView(
                  safeAreaInsets: geometry.safeAreaInsets
                )
              }
            }
        }
      }
    }
  }
  
  private struct Row: View {
    let value: Int
    
    var body: some View {
      Text("(value)")
        .frame(
          maxWidth: .infinity,
          maxHeight: .infinity,
          alignment: .leading
        )
        .listRowInsets(EdgeInsets())
        .padding()
    }
  }
  
  private struct ScrollOffsetPreferenceView: View {
    let safeAreaInsets: EdgeInsets
    
    var body: some View {
      GeometryReader { geometry in
        Color.clear
          .preference(
            key: ScrollOffsetPreferenceKey.self,
            value: offset(geometry: geometry)
          )
      }
    }
    
    private func offset(geometry: GeometryProxy) -> CGFloat {
      let safeAreaTopInset = safeAreaInsets.top
      let rowOffset = geometry.frame(in: .global).origin.y
      return rowOffset - safeAreaTopInset
    }
  }
}