Stretchableとは
そもそもStretchableなUIとはなんでしょうか。
Stretch
+ able
つまり「伸縮可能なUI」を指します。
ScrollViewの開始位置から上にスクロールしたときに、Headerがビヨーンと伸びるあれです。
ちなみに、Stretchableという言い方以外に「StretchyView」という呼び方もあるそうです。
その作り方を説明していきます!
動作環境
- MacOS Sonoma 14.1.2
- Xcode 15.0.1
- Swift 5.9
作り方
作り方としては、ScrolView
の中にGeometryReader
を入れて、画像の高さとHeaderのY軸のOffsetを計算すればできそうです。
まずは下記のような関数を作成します。
func stretchableHeaderImage(image: Image) -> some View {
GeometryReader { proxy in
image
.resizable()
.aspectRatio(contentMode: .fill)
.frame(
width: proxy.size.width,
height: getHeightForHeaderImage(proxy),
alignment: .center
)
.clipped()
.offset(y: getOffsetForHeaderImage(proxy))
}
.scaledToFill()
}
func getHeightForHeaderImage(_ proxy: GeometryProxy) -> CGFloat {
let offset = proxy.frame(in: .global).minY
let imageHeight = proxy.size.height
return offset > 0 ? imageHeight + offset : imageHeight
}
func getOffsetForHeaderImage(_ proxy: GeometryProxy) -> CGFloat {
let offset = proxy.frame(in: .global).minY
return offset > 0 ? -offset : 0
}
そしてこれらをScrollView
に入れることで、stretchableなHeaderを持つScrollViewが完成です!
・GeometryReaderの外側に.scaledToFill()
・ScrollViewの外側に.ignoresSafeArea(edges: .top)
が必要です!
コード全体
StretchableHeaderView
import SwiftUI
struct StretchableHeaderView: View {
var body: some View {
ScrollView {
stretchableHeaderImage(image: Image(systemname: "faceid"))
// ここにListなどのviewを追加します
}
.ignoresSafeArea(edges: .top)
}
func stretchableHeaderImage(image: Image) -> some View {
GeometryReader { proxy in
image
.resizable()
.aspectRatio(contentMode: .fill)
.frame(
width: proxy.size.width,
height: getHeightForHeaderImage(proxy),
alignment: .center
)
.clipped()
.offset(y: getOffsetForHeaderImage(proxy))
}
.scaledToFill()
}
func getHeightForHeaderImage(_ proxy: GeometryProxy) -> CGFloat {
let offset = proxy.frame(in: .global).minY
let imageHeight = proxy.size.height
return offset > 0 ? imageHeight + offset : imageHeight
}
func getOffsetForHeaderImage(_ proxy: GeometryProxy) -> CGFloat {
let offset = proxy.frame(in: .global).minY
return offset > 0 ? -offset : 0
}
}
#Preview {
StretchableHeaderView()
}
終わりに
ここまでお読み頂き、ありがとうございます!
株式会社ゆめみの24卒アドベントカレンダー9日目の記事でした。