我想在 SwiftUI 中重新创建名为 Gentler Streaks 的应用程序的行为。似乎有一个由图像表示的标题,当下拉时,它会粘在视图的顶部并且图像会拉伸。
在我的应用程序中,我有一个带有两个图像的标题,不知道该怎么做,代码如下。
import SwiftUI
import MapKit
struct PredatorDetail: View {
let predator: ApexPredator
@State var position: MapCameraPosition
var body: some View {
GeometryReader {geo in
ScrollView {
Section {
LazyVStack(alignment: .leading) {
//dino name
Text(predator.name)
.font(.largeTitle)
//current location
NavigationLink {
PredatorMap(position: .camera(MapCamera(centerCoordinate: predator.location, distance: 1000, heading: 250, pitch: 80)))
} label: {
Map(position: $position) {
Annotation(predator.name, coordinate: predator.location) {
Image(systemName: "mappin.and.ellipse")
.font(.largeTitle)
.imageScale(.large)
.symbolEffect(.pulse)
}
.annotationTitles(.hidden)
}
.frame(height: 125)
.overlay(alignment: .trailing) {
Image(systemName: "greaterthan")
.imageScale(.large)
.font(.title3)
.padding(.trailing, 5)
}
.overlay(alignment: .topLeading) {
Text("Current Location")
.padding([.leading, .bottom], 5)
.padding(.trailing, 8)
.background(.black.opacity(0.7))
.clipShape(.rect(bottomTrailingRadius:15))
}
.clipShape(.rect(cornerRadius: 15))
}
// apears in
Text("Appears In:")
.font(.title3)
ForEach(predator.movies, id: \.self) { movie in
Text("•" + movie)
.font(.subheadline)
}
// move momens
Text("Movie Moments:")
.font(.title)
.padding(.top, 15)
ForEach(predator.movieScenes) { scene in
Text(scene.movie)
.font(.title2)
.padding(.vertical, 1)
Text(scene.sceneDescription)
.padding(.bottom, 15)
}
Text("Read More")
.font(.caption)
Link(predator.link, destination: URL(string: predator.link)!)
.font(.caption)
.foregroundStyle(.blue)
// link to webpage
}
.padding()
.padding(.bottom, 30)
.frame(width: geo.size.width, alignment: .leading)
} header: {
ZStack (alignment: .bottomTrailing) {
// backgorund image
Image(predator.type.rawValue)
.resizable()
.scaledToFit()
.overlay {
LinearGradient(stops: [Gradient.Stop(color: .clear, location: 0.8), Gradient.Stop(color: .black, location: 1)], startPoint: .top, endPoint: .bottom)
}
// dino image
Image(predator.image)
.resizable()
.scaledToFit()
.frame(width: geo.size.width/1.5, height: geo.size.height/3)
.scaleEffect(x: -1)
.shadow(color: .black, radius: 7)
.offset(y: 30)
}
.padding(.bottom, 10)
}
}
.ignoresSafeArea()
}
.toolbarBackground(.automatic)
}
}
#Preview {
PredatorDetail(predator: Predators().apexPredators[10], position: .camera(MapCamera(centerCoordinate: Predators().apexPredators[10].location, distance: 30000)))
.preferredColorScheme(.dark)
}
我其实很无知,没有找到解决办法。
onScrollGeometryChange
来检测滚动视图何时“过度滚动”。这是当 contentOffset.y + contentInsets.top
小于 0 时。您可以使用该值来确定图像应该大多少。
例如:
struct ContentView: View {
@State var scale: CGFloat = 1
@State var offset: CGFloat = 0
var body: some View {
ScrollView {
Section {
ForEach(0..<100) { _ in
Text("Scrollable Content")
.frame(maxWidth: .infinity)
}
} header: {
Image("some image")
.resizable()
.frame(width: 100, height: 100)
.scaleEffect(scale, anchor: .top)
.offset(y: offset)
}
}
.onScrollGeometryChange(for: CGFloat.self) { geo in
-min(0, geo.contentOffset.y + geo.contentInsets.top)
} action: { _, overscrolledAmount in
scale = 1 + (overscrolledAmount / 150)
offset = -overscrolledAmount
}
}
}
这里我使用了
1 + (overscrolledAmount / 150)
,因此比例随着过度滚动的量线性变化。尝试尝试不同类型的关系(对数、平方根等)。
我还将图像向上偏移了过度滚动的量,这样它就不会与其他内容一起向下滚动。