SwiftUI:在滚动时隐藏tabBar和navigationBar

htrmnn0y  于 2023-06-28  发布在  Swift
关注(0)|答案(1)|浏览(233)

我有一个复杂的视图,其中包括一个ScrollView,我试图在用户开始滚动时隐藏tabBar和navigationBar,并在用户停止滚动时再次显示它们(有点像Apollo iOS for Reddit应用程序)。
但是,它不起作用,我知道为什么。下面是我的代码:

struct View: View {
  @State var isDragging: Bool = false
  @AppStorage("hideTopBarAndNavBarWhenScrolling") var hideTopBarAndNavBarWhenScrolling: Bool = false

  ScrollView {
    LazyVStack(spacing: 0) {
      ...
    }
  }
  .hideNavBarAndTopBar(isDragging, hideTopBarAndNavBarWhenScrolling)
  .simultaneousGesture(dragGesture)
}

  struct HideNavBarAndTopBarModifier: ViewModifier {
    var isScrollViewDragging: Bool
    var hideTopBarAndNavBarWhenScrolling: Bool

    func body(content: Content) -> some View {
        if hideTopBarAndNavBarWhenScrolling {
            Spacer()
                .frame(height: 1)
                .ignoresSafeArea()
            content
                .toolbar(isScrollViewDragging ? .visible : .hidden, for: .tabBar)
                .toolbar(isScrollViewDragging ? .visible : .hidden, for: .navigationBar)
            Spacer()
                .frame(height: 1)
                .ignoresSafeArea()
        } else {
            content
                .toolbar(.visible, for: .tabBar)
                .toolbar(.visible, for: .navigationBar)
        }
    }
}

extension View {
    func hideNavBarAndTopBar(_ isScrollViewDragging: Bool, _ hideTopBarAndNavBarWhenScrolling: Bool) -> some View {
        self.modifier(HideNavBarAndTopBarModifier(isScrollViewDragging: isScrollViewDragging, hideTopBarAndNavBarWhenScrolling: hideTopBarAndNavBarWhenScrolling))
    }
}
}

先谢谢你了!

evrscar2

evrscar21#

我创建了一些演示,你可以显示或隐藏工具栏的滚动方向和滚动范围的基础上。数字是实验性的,你可以找到你的甜蜜点。

struct ContentView: View {
    var body: some View {
        NavigationStack {
            TabView {
                ScrollableView()
            }
            .navigationTitle("Demo")
        }
        
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}


struct ScrollableView: View {
    @State var isHiding : Bool = false
    @State var scrollOffset : CGFloat = 0
    @State var threshHold : CGFloat = 0
    var body: some View {
        ScrollView {
            ZStack {
                LazyVStack {
                    ForEach(0..<300) { _ in
                        ScrollItem()
                    }
                }
                GeometryReader { proxy in
                    Color.clear
                        .changeOverlayOnScroll(
                            proxy: proxy,
                            offsetHolder: $scrollOffset,
                            thresHold: $threshHold,
                            toggle: $isHiding
                        )
                }
            }
        }
        .coordinateSpace(name: "scroll")
        .toolbar(isHiding ? .hidden : .visible, for: .navigationBar)
        .toolbar(isHiding ? .hidden : .visible, for: .tabBar)
        
    }
    
    
 // ScrollChild
struct ScrollItem: View {
        var body: some View {
            Rectangle()
                .fill(Color.red)
                .frame(minHeight: 200)
        }
    }
}



extension View {
    
    func changeOverlayOnScroll(
        proxy : GeometryProxy,
        offsetHolder : Binding<CGFloat>,
        thresHold : Binding<CGFloat>,
        toggle: Binding<Bool>
    ) -> some View {
        self
            .onChange(
                of: proxy.frame(in: .named("scroll")).minY
            ) { newValue in
                // Set current offset
                offsetHolder.wrappedValue = abs(newValue)
                // If current offset is going downward we hide overlay after 200 px.
                if offsetHolder.wrappedValue > thresHold.wrappedValue + 200 {
                    // We set thresh hold to current offset so we can remember on next iterations.
                    thresHold.wrappedValue = offsetHolder.wrappedValue
                    // Hide overlay
                    toggle.wrappedValue = true
                    
                    // If current offset is going upward we show overlay again after 200 px
                }else if offsetHolder.wrappedValue < thresHold.wrappedValue - 200 {
                    // Save current offset to threshhold
                    thresHold.wrappedValue = offsetHolder.wrappedValue
                    // Show overlay
                    toggle.wrappedValue = false
                }
         }
    }
}

相关问题