Skip to content

Instantly share code, notes, and snippets.

@1mash0
Created December 30, 2023 14:42
Show Gist options
  • Save 1mash0/0774712b765fe69044f7d0b2cf16a804 to your computer and use it in GitHub Desktop.
Save 1mash0/0774712b765fe69044f7d0b2cf16a804 to your computer and use it in GitHub Desktop.
真ん中にアイコンがあって下スクロールしたらヘッダーが伸びる&ブラー効果して
import SwiftUI
struct ContentView: View {
@State private var initOffset: CGFloat = .zero
@State private var offset: CGFloat = .zero
@State private var headerHeight: CGFloat = 300
@State private var scale: CGFloat = 1.0
@State private var blurRadius: CGFloat = .zero
let defaultHeaderHeight: CGFloat = 300
let iconHeight: CGFloat = 200
var body: some View {
ZStack(alignment: .topTrailing) {
ScrollView {
ZStack {
LazyVStack(spacing: 0) {
ForEach(0..<50, id: \.self) { i in
if i == 0 {
Spacer()
Circle()
.fill(.yellow)
.stroke(.primary, lineWidth: 4.0)
.frame(width: iconHeight, height: iconHeight)
.overlay {
Text("Icon")
.font(.title)
}
.scaleEffect(scale < 1.0 ? scale : 1.0, anchor: .bottom)
Spacer()
} else {
Text("item \(i)")
.frame(maxWidth: .infinity, minHeight: 44)
.background(.white)
}
}
}
.padding(.top, defaultHeaderHeight - (iconHeight / 2))
.zIndex(scale == 0.5 ? 0.0 : 1.0)
GeometryReader { gr in
Color.cyan
.frame(height: headerHeight)
.overlay {
VStack {
Text("Header")
}
}
.blur(radius: blurRadius)
.onAppear {
initOffset = gr.frame(in: .global).origin.y
}
.offset(y: gr.frame(in: .global).origin.y < initOffset
? abs(gr.frame(in: .global).origin.y)
: initOffset - gr.frame(in: .global).origin.y)
.onChange(of: gr.frame(in: .global).origin.y, initial: true) { _, newValue in
offset = gr.frame(in: .global).minY
blurRadius = self.calcBlurRadius(maxRadius: 3.0, yOffset: offset)
headerHeight = self.calcHeaderHeight(
minHeight: defaultHeaderHeight / 3,
maxHeight: defaultHeaderHeight,
yOffset: offset
)
scale = self.calcScale(minScale: 0.5, maxScale: 1.0, headerHeight: headerHeight)
}
}
}
}
.ignoresSafeArea(edges: .vertical)
.background(.gray)
}
}
func calcHeaderHeight(minHeight: CGFloat, maxHeight: CGFloat, yOffset: CGFloat) -> CGFloat {
if maxHeight + yOffset < minHeight {
return minHeight
}
return maxHeight + yOffset
}
func calcBlurRadius(maxRadius: CGFloat, yOffset: CGFloat) -> CGFloat {
if yOffset - initOffset < 0 {
return 0.0
}
return yOffset - initOffset < maxRadius ? yOffset - initOffset : maxRadius
}
func calcScale(minScale: CGFloat, maxScale: CGFloat, headerHeight: CGFloat) -> CGFloat {
if headerHeight == defaultHeaderHeight {
return maxScale
}
return headerHeight / defaultHeaderHeight < minScale ? minScale : headerHeight / defaultHeaderHeight
}
}
#Preview {
ContentView()
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment