#ios #animation #swiftui
#iOS #Анимация #свифтуи
Вопрос:
Я пытаюсь создать представление, в котором заголовок фиксируется в верхней части представления и изменяет его размер в соответствии со смещением прокрутки, когда смещение равно 0, заголовок становится больше, а когда пользователь прокручивает заголовок, он становится меньше
struct ContentView : View {
@State var largeHeader = true
var body: some View {
VStack {
Text("HEADER").padding(.vertical, largeHeader ? 30 : 10)
Divider()
ScrollView {
VStack {
Text("Content0")
.padding()
Text("Content1")
.padding()
Text("Content2")
.padding()
}
.background(GeometryReader { geometryProxy -> Color in
DispatchQueue.main.async {
largeHeader = geometryProxy.frame(in: .named("myspace")).minY >= 0
}
return Color.clear
})
}
.coordinateSpace(name: "myspace")
}.animation(.default)
}
}
Это работает нормально, когда содержимое прокрутки длиннее, но когда содержимого мало, как в приведенном выше коде, я получаю это мерцание (на устройстве это еще хуже, но качество gif низкое).
Есть идеи, как это исправить?
Ответ №1:
Похоже, что происходит некоторое вмешательство.
Я нашел два обходных решения, это зависит от желаемого эффекта.
Решение 1
Идея: Использовать ZStack
так, чтобы ScrollView
и ваш заголовок не мешали.
struct ContentView: View {
@State var largeHeader = true
var body: some View {
ZStack {
ScrollView {
VStack {
ForEach(0..<3) { i in
Text("Content(i)")
.padding()
}
}
.background(GeometryReader { geometryProxy -> Color in
DispatchQueue.main.async {
largeHeader = geometryProxy.frame(in: .named("1")).minY >= 0
}
return Color.clear
})
}
.coordinateSpace(name: "1")
.offset(y: largeHeader ? 100 : 60)
VStack {
VStack {
Spacer()
Text("HEADER")
.padding()
Divider()
}
.frame(maxWidth: .infinity)
.frame(height: largeHeader ? 140 : 100)
.background(Color.white)
Spacer()
}
.edgesIgnoringSafeArea(.all)
}
.animation(.default)
}
}
Заголовок этого заголовка всегда будет изменять высоту, независимо от того, насколько велика высота содержимого.
Решение 2
Идея: изменять высоту заголовка только тогда, когда достаточно содержимого для прокрутки.
Решение: определение высоты содержимого scrollview.
struct ContentView: View {
@State var largeHeader = true
@State var scrollViewScrollable = false
var body: some View {
VStack {
Text("HEADER").padding(.vertical, largeHeader ? 30 : 10)
Divider()
ScrollView {
VStack {
ForEach(0..<3) { i in
Text("Content(i)")
.padding()
}
}
.background(GeometryReader { geometryProxy -> Color in
if scrollViewScrollable {
DispatchQueue.main.async {
largeHeader = geometryProxy.frame(in: .named("1")).minY >= 0
}
}
return Color.clear
})
.background(
GeometryReader { proxy in
Color.clear.onAppear {
scrollViewScrollable = proxy.frame(in: .named("1")).size.height >= UIScreen.main.bounds.size.height - 100
}
}
)
}
.coordinateSpace(name: "1")
}
.animation(.default)
}
}