美文网首页
实现SwiftUI下带头部嵌套滚动的页面框架

实现SwiftUI下带头部嵌套滚动的页面框架

作者: zackzheng | 来源:发表于2024-09-17 16:42 被阅读0次

    实现了SwiftUI下带头部嵌套滚动的页面框架,目前有两种实现方案:

    • 方案一
    1. 监听页面手势,实时改变header的高度,手势停止时,修改header的高度为完全消失或完全出现,即自动吸附。
    2. 根据header的高度情况,设置页面是否可滚动。
    struct HeaderBarPagerView<Header: View, Tab: Hashable, TabItem: View, TabPage: View>: View {
    
        /// 参数
        var header: () -> Header
    
        let tabList: [Tab]
        @Binding var selectedTab: Tab
        let tabItemHeight: CGFloat
        let tabItem: (_ tab: Tab, _ isSelected: Bool) -> TabItem
        let showSlider: Bool
        let tabEdgeInsets: EdgeInsets
        let tabPage: (_ tab: Tab, _ isSelected: Bool, _ didScroll: ((CGFloat) -> Void)?) -> TabPage
        
        /// 其他
        @State private var headerSize: CGSize = .zero
        
        /// 手势
        @GestureState private var dragValue: CGSize = .zero
        @State private var preDragValue = CGSize.zero
    
        var body: some View {
    
            VStack(spacing: 0) {
                
                ZStack(alignment: .bottom) {
                    ChildSizeReader(size: $headerSize) {
                        self.header()
                    }
                }
                .frame(height: min(max(headerSize.height + preDragValue.height + dragValue.height, 0), headerSize.height))
    
                BarPagerView(tabList: tabList,
                             selectedTab: $selectedTab,
                             tabItemHeight: tabItemHeight,
                             tabItem: tabItem,
                             showSlider: showSlider,
                             tabEdgeInsets: tabEdgeInsets,
                             tabPage: { tab, isSelected in
    
                    tabPage(tab, isSelected, { offset in
                        
                        if offset < 0 {
                            withAnimation {
                                self.preDragValue.height = 0
                            }
                        }
                    })
                    .scrollDisabled(headerSize.height + dragValue.height + preDragValue.height > 0)
                })
            }
            .gesture(
                
                DragGesture()
                    .updating($dragValue, body: { value, state, _ in
                        state = value.translation
                    })
                    .onEnded { value in
                        
                        let newDragHeight = self.preDragValue.height + value.translation.height
                        let oldDragHeight = self.preDragValue.height
                        self.preDragValue.height = newDragHeight
                        withAnimation {
                            self.preDragValue.height = newDragHeight > oldDragHeight ? 0 : -headerSize.height
                        }
                    }
            )
        }
    }
    
    • 方案二
    1. 监听页面的滚动距离,回调页面框架。
    2. 页面框架根据滚动距离,协同调整header的高度
    struct HeaderBarPagerSynchronousView<Header: View, Tab: Hashable, TabItem: View, TabPage: View>: View {
    
        /// 参数
        var header: () -> Header
    
        let tabList: [Tab]
        @Binding var selectedTab: Tab
        let tabItemHeight: CGFloat
        let tabItem: (_ tab: Tab, _ isSelected: Bool) -> TabItem
        let showSlider: Bool
        let tabEdgeInsets: EdgeInsets
        let tabPage: (_ tab: Tab, _ isSelected: Bool, _ didScroll: ((CGFloat) -> Void)?) -> TabPage
        
        /// 其他
        @State private var headerSize: CGSize = .zero
    
        @State private var preDragValue = CGSize.zero
    
        var body: some View {
    
            VStack(spacing: 0) {
                
                ZStack(alignment: .bottom) {
                    ChildSizeReader(size: $headerSize) {
                        self.header()
                    }
                }
                .frame(height: min(max(headerSize.height + preDragValue.height, 0), headerSize.height))
    
                BarPagerView(tabList: tabList,
                             selectedTab: $selectedTab,
                             tabItemHeight: tabItemHeight,
                             tabItem: tabItem,
                             showSlider: showSlider,
                             tabEdgeInsets: tabEdgeInsets,
                             tabPage: { tab, isSelected in
    
                    tabPage(tab, isSelected, { offset in
                        self.preDragValue.height = -offset
                    })
                })
            }
        }
    }
    

    本文 DEMO 链接:
    https://github.com/sapphirezzz/ScrollWithHeader-SwiftUI-Demo

    相关文章

      网友评论

          本文标题:实现SwiftUI下带头部嵌套滚动的页面框架

          本文链接:https://www.haomeiwen.com/subject/qamgljtx.html