实现了SwiftUI
下带头部嵌套滚动的页面框架,目前有两种实现方案:
- 方案一
- 监听页面手势,实时改变
header
的高度,手势停止时,修改header
的高度为完全消失或完全出现,即自动吸附。 - 根据
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
}
}
)
}
}
- 方案二
- 监听页面的滚动距离,回调页面框架。
- 页面框架根据滚动距离,协同调整
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
网友评论