Skip to content

Instantly share code, notes, and snippets.

@unixzii
Created November 7, 2023 13:21
Show Gist options
  • Star 26 You must be signed in to star a gist
  • Fork 6 You must be signed in to fork a gist
  • Save unixzii/540f3755862d0d437bda3928e59de871 to your computer and use it in GitHub Desktop.
Save unixzii/540f3755862d0d437bda3928e59de871 to your computer and use it in GitHub Desktop.
A demo of implementing iOS Weather card in SwiftUI.
import SwiftUI
struct HeaderView: View {
var body: some View {
HStack {
Image(systemName: "info.circle.fill")
.resizable()
.frame(width: 12, height: 12)
Text("Section Header")
.font(.system(size: 13))
Spacer()
}
}
}
struct CardView: View {
let index: Int
let coordinateSpace: CoordinateSpace
private let headerHeight: CGFloat = 20
@State private var offset: CGFloat = 0
@State private var cellHeight: CGFloat = 0
var maxOffset: CGFloat {
cellHeight - headerHeight - 16
}
var body: some View {
ZStack {
VStack(alignment: .leading, spacing: 0) {
HeaderView()
.frame(height: headerHeight)
.padding(.bottom, 4)
.offset(y: offset < 0 ? min(-offset, maxOffset) : 0)
VStack(alignment: .leading) {
Text("\(index + 1) - Title")
.font(.system(size: 16))
.bold()
.padding(.bottom, 2)
Text("This is description text...")
.font(.system(size: 13))
}
.clipShape(.rect().offset(y: offset < 0 ? -offset : 0))
}
.padding(EdgeInsets(top: 8, leading: 12, bottom: 12, trailing: 12))
.background(Material.thin)
.clipShape(.rect(cornerSize: .init(width: 8, height: 8), style: .continuous))
.offset(y: offset < -maxOffset ? (-offset - maxOffset) : 0)
.opacity(offset < -maxOffset ? (1 - (-offset - maxOffset) / 22.0) : 1)
}
.background(GeometryReader { reader in
Color.clear
.onChange(of: reader.frame(in: coordinateSpace)) { oldValue, newValue in
offset = newValue.minY
}
.onAppear {
let frame = reader.frame(in: coordinateSpace)
offset = frame.minY
cellHeight = frame.height
}
})
}
}
struct WeatherView: View {
@State private var coordinateSpaceName = UUID()
var body: some View {
VStack {
Color.clear
.frame(height: 128)
ScrollView {
LazyVStack {
ForEach(0..<20) { index in
CardView(index: index, coordinateSpace: .named(coordinateSpaceName))
}
}
}
.coordinateSpace(.named(coordinateSpaceName))
.clipShape(.rect(cornerSize: .init(width: 8, height: 8), style: .continuous))
.padding(.horizontal, 8)
.ignoresSafeArea(.all, edges: .bottom)
}
.background(Image("Background"))
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment