SwiftUI head retractable ScrollView
Results show
code
CollapsibleHeaderScrollView code
//
// CollapsibleHeaderScrollView.swift
// CollapsibleHeader
//
// Created by RandyWei on 2021/9/3.
//
import SwiftUI
struct CollapsibleHeaderScrollView: View {
// Get the security zone
private let safeAreaInsets = UIApplication.shared.windows.first?.safeAreaInsets
// Navigation bar Padding
private let padding: CGFloat = 8.0
// Height of the navigation bar
private var navigationBarHeight: CGFloat {
// The navigation bar assumes a height of 45, which can be obtained from the code
// Navigation bar height + stream + defined upper and lower padding
45 + (safeAreaInsets?.top ?? 0) + padding * 2
}
// Define the maximum size of the scaling area at the top. Set this to 350, depending on your needs
private let collapsibleHeaderMaxHeight: CGFloat = 350
// We need to calculate the scroll offset of the ScrollView
/ / the offset
@State var offset: CGFloat = 0
// Retractable area transparency
private var collapsibleHeaderOpacity: Double{
// Calculate according to offset to achieve gradient transparency :1, to be opaque to transparent, so need 1- calculated value; 2, you can increase the height of the navigation bar to achieve better results
1 - Double(-offset / (collapsibleHeaderMaxHeight + navigationBarHeight))
}
// Navigation bar left transparency
private var navLeftViewOpacity:Double{
Double(-offset / (collapsibleHeaderMaxHeight + navigationBarHeight))
}
var body: some View {
ScrollView(.vertical, showsIndicators: false) {
VStack{
// The top can scale the contents of the area
GeometryReader{proxy in
VStack{
/ / big head
Image("avatar")
.resizable()
.aspectRatio(contentMode: .fill)
.frame(width: 150, height: 150)
.clipShape(Circle())
/ / nickname
Text("Sir William.")
.font(.title)
.bold()
// Signature
Text("This man is lazy and has nothing left.")
}
.foregroundColor(.white)
.padding(.bottom)
.frame(maxWidth: .infinity)
.frame(height: calcNavHeight(),alignment: .bottom)
.opacity(collapsibleHeaderOpacity)
.background(Color.blue)
/ / the navigation bar
.overlay(
HStack{
// Put it in the wrong place
/ / small head
Image("avatar")
.resizable()
.aspectRatio(contentMode: .fill)
.frame(width: 40, height: 40, alignment: .center)
.clipShape(Circle())
.opacity(navLeftViewOpacity)
Text("Sir William.")
.opacity(navLeftViewOpacity)
Spacer(a)Image(systemName: "gearshape")
}
.padding(.top, (safeAreaInsets?.top ?? 0) + padding)
.foregroundColor(.white)
.padding(.horizontal)
.frame(height: navigationBarHeight),
alignment: .top
)
}
.frame(height: collapsibleHeaderMaxHeight)
.offset(y: -offset)
.zIndex(1)
// Scroll through content
VStack{
ForEach(0..<50) {_ in
HStack{
// Left icon
Image(systemName: "person")
.resizable()
.aspectRatio(contentMode: .fit)
.frame(width: 80, height: 80, alignment: .center)
VStack(alignment: .leading){
Text("titletitletitletitletitle")
.font(.title)
Spacer(a)Text("bodybodybodybodybodybody")
.font(.body)
}
.frame(maxWidth: .infinity,alignment: .leading)
}
.padding(.horizontal)
}
}
// It is only used as a placeholder for demonstration. The specific situation depends on the actual project data
.redacted(reason: .placeholder)
}
.modifier(OffsetViewModifier(offset: $offset))}// Define the scroll view space name
.coordinateSpace(name: "CollapsibleScrollView")}/// Calculate the size of the scaling area
func calcNavHeight(a) -> CGFloat {
let height = collapsibleHeaderMaxHeight + offset
return height < navigationBarHeight ? navigationBarHeight : height
}
}
struct CollapsibleHeaderScrollView_Previews: PreviewProvider {
static var previews: some View {
ContentView()}}Copy the code
OffsetViewModifier code
//
// OffsetViewModifier.swift
// CollapsibleHeader
//
// Created by RandyWei on 2021/9/3.
//
import SwiftUI
struct OffsetViewModifier:ViewModifier {
@Binding var offset:CGFloat
func body(content: Content) -> some View {
content.overlay(
GeometryReader{proxy -> Color in
// The offset of the view in the scrollView is obtained from the position space
let minY = proxy.frame(in: .named("CollapsibleScrollView")).minY
DispatchQueue.main.async {
self.offset = minY
}
return Color.clear
},
alignment: .top
)
}
}
Copy the code
ContentView code
import SwiftUI
struct ContentView: View {
var body: some View {
CollapsibleHeaderScrollView()
.ignoresSafeArea()
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()}}Copy the code
Video tutorial
SwiftUI head retractable ScrollView