SwiftUI 实现依附在顶部标题栏的视图
发布
更新
字数
249
阅读
2 分钟
阅读量
996
通过两层 GeometryReader
读取 ScrollView
内容及置顶视图的位置信息进行处理,可以实现在滚动时,置顶内容固定在顶部,并随着导航标题栏大小标题样式切换而自动适应位置。同时为置顶内容增加了阴影效果,会随着上下滚动深浅变化。
import SwiftUI
struct AffixTop: ViewModifier {
var selfGeometry: GeometryProxy
var geometry: GeometryProxy
var always: Bool
private var offsetY: CGFloat {
always ? geometry.frame(in: .global).minY - selfGeometry.frame(in: .global).minY : max(0, geometry.frame(in: .global).minY - selfGeometry.frame(in: .global).minY)
}
func body(content: Content) -> some View {
content
.offset(y: offsetY)
.shadow(
color: Color(.sRGBLinear, white: 0, opacity: min(offsetY / 40 * 0.12, 0.12)),
radius: min(offsetY / 10, 4),
y: min(offsetY / 10, 4)
)
}
}
extension View {
func affixTop(_ selfGeometry: GeometryProxy, outer geometry: GeometryProxy, always: Bool = false) -> some View {
modifier(AffixTop(selfGeometry: selfGeometry, geometry: geometry, always: always))
}
}
struct AffixTop_Previews: PreviewProvider {
static var previews: some View {
NavigationView {
GeometryReader { geometry in
ScrollView {
VStack {
Text("SwiftDict").frame(width: geometry.size.width, height: 400)
Text("swiftdict.com").frame(width: geometry.size.width, height: 500).background(.orange)
}
.overlay {
GeometryReader { selfGeometry in
Text("Affix").frame(width: geometry.size.width, height: 44).background().affixTop(selfGeometry, outer: geometry, always: true)
}
}
}
}
.navigationTitle("Affix top")
.navigationBarTitleDisplayMode(.inline)
}
}
}