SwiftUI не будет отражать изменения в переменной @Binding @State, когда изменение выполняется из GeometryReader - PullRequest
0 голосов
/ 22 апреля 2020

У меня есть 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

Может кто-нибудь объяснить, что здесь происходит? Это предполагаемое поведение или ошибка?

...