Quantcast
Viewing latest article 5
Browse Latest Browse All 644

How to collapse and Fade Header in SwiftUI

I am currently trying to implement a scroll to hide header. How can I shrink the height of the header and fade it in as the user scrolls down. Then do the opposite when the user scrolls up(expand the header height to its initial value and fade it out).I have tried animating the opacity but it wasn't smooth. Here is the code for hiding and snapping the heading based on scroll direction.

   struct ScrollToHideView: View {    @State private var naturalScrollOffset: CGFloat = 0    @State private var lastNaturalOffset: CGFloat = 0    @State private var headerOffset: CGFloat = 0    @State private var isScrollingUp = false    @State private var opacity = 1.0    @State private var tempH = 0.0    @State private var top = 0.0    var body: some View {        GeometryReader {            let safeArea = $0.safeAreaInsets            let headerHeight = 60.0 + safeArea.top            ScrollView(.vertical) {                LazyVStack {                    ForEach(0..<10, id: \.self) { index in                        DummyView()                    }                }                .padding(16)            }            .overlay(content: {                 Text("\(naturalScrollOffset)")            })            .safeAreaInset(edge: .top, spacing: 0, content: {                HeaderView()                    .padding(.bottom, 16)                    .frame(height: headerHeight, alignment: .bottom)                    .background(.blue)                    .opacity(opacity)                    .offset(y: -headerOffset)            })            .onScrollGeometryChange(for: CGFloat.self) { proxy in                let maxHeight = proxy.contentSize.height - proxy.containerSize.height                return max(min(proxy.contentOffset.y + headerHeight, maxHeight),0)            } action: { oldValue, newValue in                let isScrollingUp = oldValue < newValue                headerOffset = min(max(newValue - lastNaturalOffset, 0), headerHeight)                self.isScrollingUp = isScrollingUp                // animating opacity                withAnimation(.easeIn(duration: 2)) {                    if self.isScrollingUp {                        opacity = 0                    } else {                        opacity = 1                    }                }                naturalScrollOffset = newValue            }            .onScrollPhaseChange({ oldPhase, newPhase, context in                if !newPhase.isScrolling &&                    (headerOffset != 0 || headerOffset != headerHeight) {                    withAnimation(.snappy(duration: 0.25, extraBounce: 0)) {                        if headerOffset > (headerHeight * 0.5) &&                            naturalScrollOffset > headerHeight {                            headerOffset = headerHeight                        } else {                            headerOffset = 0                        }                        lastNaturalOffset = naturalScrollOffset - headerOffset                    }                }            })            .onChange(of: isScrollingUp) { oldValue, newValue in                lastNaturalOffset = naturalScrollOffset - headerOffset            }            .ignoresSafeArea(.container, edges: .top)        }    }}extension ScrollToHideView {    @ViewBuilder func HeaderView() -> some View {        HStack(spacing: 20) {            Image("user1")                .resizable()                .aspectRatio(contentMode: .fit)                .frame(height: 25)            Spacer(minLength: 0)            Button("", systemImage: "airplayvideo") {            }            Button("", systemImage: "bell") {            }            Button("", systemImage: "magnifyingglass") {            }        }        .font(.title2)        .foregroundStyle(.primary)        .padding(.horizontal, 16)    }    @ViewBuilder    func DummyView() -> some View {        VStack(alignment: .leading, spacing: 6) {            RoundedRectangle(cornerRadius: 6)                .frame(height: 220)            HStack(spacing: 10) {                Circle()                    .frame(width: 45, height: 45)                VStack(alignment: .leading, spacing: 4) {                    Rectangle()                        .frame(height: 10)                    HStack {                        Rectangle()                            .frame(width: 100)                        Rectangle()                            .frame(width: 80)                        Rectangle()                            .frame(width: 80)                    }                    .frame(height: 10.0)                }            }        }        .foregroundStyle(.tertiary)    }}

Viewing latest article 5
Browse Latest Browse All 644

Trending Articles