Large icon+title header at rest; compact gas-pump bar appears only after scrolling (tracker on header row background)

This commit is contained in:
FuelBoard Contributor
2026-08-11 21:59:32 +01:00
parent 644342ae63
commit 8d24de401d
+44 -1
View File
@@ -22,10 +22,37 @@ struct StationsView: View {
/// which station is "best".
@State private var pageSize = 10
@State private var visibleCount = 10
/// True once the list has scrolled the large header title is shown at
/// rest; the compact gas-pump+title bar appears only after scrolling.
@State private var isScrolled = false
var body: some View {
NavigationStack {
List {
// Large title header (icon + title). Native navigation titles
// can't carry an icon, so this is a real row; the scroll
// tracker rides on its background so no extra row is created.
HStack(spacing: 10) {
Image(systemName: "fuelpump.fill")
.font(.system(size: 34))
.foregroundStyle(selectedFuel.tintColor)
Text("FuelBoard")
.font(.largeTitle.bold())
}
.frame(maxWidth: .infinity, alignment: .leading)
.padding(.vertical, 6)
.listRowSeparator(.hidden)
.listRowInsets(EdgeInsets(top: 0, leading: 16, bottom: 0, trailing: 16))
.listRowBackground(Color.clear)
.background(
GeometryReader { proxy in
Color.clear.preference(
key: ScrollOffsetKey.self,
value: proxy.frame(in: .named("stationsScroll")).minY
)
}
)
Section {
if let location {
if sortMode == .closest {
@@ -180,24 +207,40 @@ struct StationsView: View {
// New fetch or filter switch back to the first page.
visibleCount = pageSize
}
.coordinateSpace(name: "stationsScroll")
.onPreferenceChange(ScrollOffsetKey.self) { minY in
isScrolled = minY < -60
}
.toolbar {
ToolbarItem(placement: .principal) {
if isScrolled {
HStack(spacing: 6) {
Image(systemName: "fuelpump.fill")
.foregroundStyle(selectedFuel.tintColor)
Text("FuelBoard")
.font(.headline)
}
.transition(.opacity)
}
}
}
.navigationBarTitleDisplayMode(.inline)
.navigationTitle("FuelBoard")
}
}
}
// MARK: - Fuel-type iconography (app target only FuelStore.swift is Foundation-only)
/// Scroll offset preference the large-title header row reports its position
/// in the list's coordinate space so we know when it has scrolled under the
/// nav bar (minY < -60) and can show the compact gas-pump+title bar.
private struct ScrollOffsetKey: PreferenceKey {
static var defaultValue: CGFloat = 0
static func reduce(value: inout CGFloat, nextValue: () -> CGFloat) {
value = nextValue()
}
}
extension FuelType {
/// Short segment label ("Unleaded" / "Premium" / "Diesel") for the picker.
var shortName: String {