У меня есть ScrollView с HStack представлений, которые будут анимироваться в зависимости от их собственной позиции. Для этого я использую GeometryReader, который считывает текущую глобальную позицию каждого вида, и когда достигается определенная позиция, вид переключается из не в фокусе в состояние в фокусе и выполняет некоторые преобразования и изменяет переменную @State на указывает на то, что представление находится в фокусе, так что другие части представления могут воздействовать на него.
Довольно просто, верно? К сожалению, когда я изменяю @State из GeometryReader, изменение состояния не произойдет. Поэтому я построил упрощенную версию, чтобы продемонстрировать проблему.
Вот код:
import SwiftUI
struct GeometryReaderTest: View {
var body: some View {
ScrollView(.horizontal, showsIndicators: false) {
//
HStack(spacing: 40){
ForEach(0..<10) { _ in
SlideView()
}
}
}
}
}
struct SlideView : View {
//
@State var isInFocus : Bool = false
var body: some View {
ZStack {
Rectangle().fill( isInFocus ? Color.green : Color.orange).frame(width: UIScreen.main.bounds.width - 60, height: 120, alignment: .center)
MyContent(isInFocus: self.$isInFocus)
}
}
}
struct MyContent : View {
@Binding var isInFocus : Bool
var body: some View {
GeometryReader { geo in
self.toggleFocusState(geometry: geo)
}
}
func toggleFocusState(geometry : GeometryProxy)-> some View{
let distance = geometry.frame(in: .global).origin.x.magnitude
self.isInFocus = distance < 120
return VStack {
Text("Focused: \(self.isInFocus ? "Yes" : "Nope" )")
Text("Distance: \(distance)")
Button(action: {
//
self.isInFocus.toggle()
}) {
Text("Toggle")
}
}
}
}
struct GeometryReaderTest_Previews: PreviewProvider {
static var previews: some View {
GeometryReaderTest()
}
}
Если вы нажмете кнопку «Переключатель», которая также запускается из GeometryReader, переменная @State будет успешно изменена, и изменение будет отражение.
Когда вы на самом деле прокручиваете ScrollView и оставляете его для естественной прокрутки, ничего не произойдет. Он не будет обновляться даже после остановки.
см. Здесь: https://streamable.com/d3op74
Когда вы медленно прокручиваете ScrollView и не поднимаете палец, переменная @State изменится.
здесь: https://streamable.com/7m15t9
Если вы введете задержку с DispatchQueue.main.asyncAfter () следующим образом:
DispatchQueue.main.asyncAfter(deadline: .now() + 0.0) {
self.isInFocus = distance < 120
}
, даже если задержка равна 0, Изменение @State будет работать при прокрутке, независимо от того, насколько быстро на этот раз кнопка переключения не будет работать (что имеет смысл, поскольку GeometryReader пересчитает и отменит действие, выполненное кнопкой).
здесь: https://streamable.com/q3ylu1
Может кто-нибудь объяснить, что здесь происходит? Это предполагаемое поведение или ошибка?