Перезагрузите SwiftUI view из него

#view #swiftui #reload

#Вид #swiftui #перезагрузите

Вопрос:

У меня есть некоторый текст внутри представления, и я хочу, чтобы этот текст изменил его положение по таймеру. У меня есть следующее:

 struct AlphabetView: View {
    @State var timer: Publishers.Autoconnect<Timer.TimerPublisher> = Timer.publish(every: 0.1, on: .main, in: .common).autoconnect()
    @State var refreshMe: Bool = false // this is a hack to refresh the view
    
    var relativePositionX: CGFloat {
        get { return CGFloat(Float.random(in: 0...1)) }
    }
    
    var relativePositionY: CGFloat {
        get { return CGFloat(Float.random(in: 0...1)) }
    }
    
    var body: some View {
        GeometryReader { geometry in
            Text("Hello World!")
                .position(x: geometry.size.width * self.relativePositionX, y: geometry.size.height * self.relativePositionY)
                .onReceive(timer) { _ in
                    // a hack to refresh the view
                    self.refreshMe = !self.refreshMe
                }
        }
    }
}
  

Я полагаю, что представление должно перезагружаться каждый раз, когда изменяется self.refreshMe, потому что это @State . Но я вижу, что положение текста изменяется только при перезагрузке родительского представления рассматриваемого представления. Что я делаю не так (кроме взлома)? Есть ли лучший способ сделать это?

Комментарии:

1. Ваш хак не работает, потому что ваш view фактически не используется refreshMe . Достаточно добавить что-то вроде .foregroundColor(self.refreshMe ? .black : .black) , чтобы SwiftUI запустил обновление.

2. Кстати, CGFloat тоже есть .random(in:) , так var relativePositionX: CGFloat { .random(in: 0...1) } что этого достаточно.

Ответ №1:

Вместо взлома просто обновите позицию напрямую.

Вот исправленный вариант. Протестировано с Xcode 12 / iOS 14.

 struct AlphabetView: View {
    let timer: Publishers.Autoconnect<Timer.TimerPublisher> = Timer.publish(every: 0.1, on: .main, in: .common).autoconnect()

    @State var point: CGPoint = .zero
    
    var relativePositionX: CGFloat {
        get { return CGFloat(Float.random(in: 0...1)) }
    }
    
    var relativePositionY: CGFloat {
        get { return CGFloat(Float.random(in: 0...1)) }
    }
    
    var body: some View {
        GeometryReader { geometry in
            Text("Hello World!")
                .position(self.point)
                .onReceive(timer) { _ in
                    self.point = CGPoint(x: geometry.size.width * self.relativePositionX, y: geometry.size.height * self.relativePositionY)
                }
        }
    }
}
  

Комментарии:

1. Это полностью решает проблему, большое вам спасибо.