我正在尝试更改标题(“我的标题”)上的字体和填充?因此,我将
.navigationTitle
设置为具有良好的列表行为,当您滚动经过标题时,它会更新导航栏标题。
注意:我也喜欢保留导航栏标题自动更改的行为
这是我的代码:
#Preview() {
NavigationView {
List {
ForEach(1..<30) { number in
Text("\(number)")
}.navigationTitle("My Title")
}
}
}
这是我想出的自定义解决方案。它使用 PreferenceKey 和 GeometryReader 来确定滚动偏移。
struct ContentView: View {
@State var offsetValue: CGFloat = 1
@State private var titlePlacement: Alignment = .topLeading
var body: some View {
NavigationStack {
GeometryReader { proxy in
let scrollViewHeight = proxy.frame(in: .scrollView(axis: .vertical)).height
let minY = proxy.frame(in: .scrollView(axis: .vertical)).minY
ScrollView {
ZStack {
LazyVStack {
ForEach(0...100, id: \.self) { index in
Text("Row \(index)")
}
}
.padding(.top, 40)
GeometryReader { proxy in
let offset = proxy.frame(in: .named("scroll")).minY
Color.clear.preference(key: OffsetKey.self, value: offset)
}
} //: ZSTACK
} //: SCROLL
.coordinateSpace(name: "scroll")
.onPreferenceChange(OffsetKey.self) { scrollValue in
let progress = -minY / scrollValue
/// Cap it between 1-0
let cappedScrollValue = min(max(abs(progress), 0), 1)
print("Capped: \(cappedScrollValue)")
withAnimation( /* YOUR ANIMATON HERE */) {
if offsetValue >= 0.8 {
titlePlacement = .topLeading
} else {
titlePlacement = .top
}
}
offsetValue = cappedScrollValue
}
} //: GEOMETRY
.overlay(alignment: titlePlacement) {
Text("My Title")
.font(.title.bold())
.frame(maxWidth: .infinity, alignment: titlePlacement)
.padding(.leading, 20) // <-- Padding here
.background(alignment: .top) {
if titlePlacement == .top {
Rectangle()
.fill(.ultraThinMaterial)
.frame(maxWidth: .infinity)
.frame(height: 100)
.offset(y: -60)
}
}
}
} //: NAVIGATION
}
}
struct OffsetKey: PreferenceKey {
typealias Value = CGFloat
static var defaultValue = CGFloat.zero
static func reduce(value: inout Value, nextValue: () -> Value) {
value += nextValue()
}
}
我跟踪两个状态变量:当然是偏移量,还有标题的位置。当我拥有标准导航栏的外观和感觉时,我尝试尽可能多地复制。该解决方案允许进行更深入的自定义,因为您可以将任何所需的视图放置在标题所在的覆盖层中。但绝对还有改进的空间。结果:
让我知道这是否适合您!