Как мне запустить updateUIView для UIViewRepresentable?

#swift #swiftui

#swift #swiftui

Вопрос:

Я пытаюсь внедрить UIView из SpritzSwift в приложение SwiftUI, но после первого рендеринга я не могу его обновить. Менеджер, который управляет UIView, работает, но сам UIView не обновляется. Я ожидал, что либо UIView.setNeedsDisplay() внутри контроллера представления, либо изменения в переменных @Bindable внутри оболочки вызовут updateUIView, но без кубиков.

Независимо от того, какие изменения я вношу в UIView или в его оболочку, он никогда не обновляется (например, фон никогда не обновляется до чистого цвета в примере кода). Как мне обновить это представление?

Вот код SwiftUI:

 import SwiftUI
struct Content: View {

    @State public var ssManager:SpritzSwiftManager = SpritzSwiftManager(withText: "", andWordPerMinute: Int(200))
    @State public var ssView:SpritzSwiftView = SpritzSwiftView(frame: CGRect(x: 0, y: 0, width: 200, height: 600 ))
    @State private var currentWord = ""
    
    var body: some View {
        VStack {
            Text("SpritzTest")
                .padding()
            let spritzUIView = SpritzUIViewRepresentable(SpritzView: $ssView,SpritzViewManager:$ssManager, CurrentWord: $currentWord)
            spritzUIView.padding()
            Button(action:
                    {
                        ssManager  = SpritzSwiftManager(withText: "Text try one two three", andWordPerMinute: 200)
                        spritzUIView.SpritzView = SpritzSwiftView(frame: CGRect(x: 0, y: 0, width: 200, height: 40 ))
                        spritzUIView.SpritzView.backgroundColor = .clear
                        ssManager.startReading { (word, finished) in
                            if !finished {
                                self.ssView.updateWord(word!)
                                currentWord = word!.word
                                spritzUIView.CurrentWord = currentWord

                            }
                        }
                    })
            {
                Text("Start")
            }
        }
    }
}
 

и вот оболочка:

 struct SpritzUIViewRepresentable : UIViewRepresentable{
    @Binding var SpritzView:SpritzSwiftView
    @Binding var SpritzViewManager:SpritzSwiftManager
    @Binding var CurrentWord:String
    
    func makeUIView(context: Context) -> SpritzSwiftView {
           return SpritzView
       }
       func updateUIView(_ uiView: SpritzSwiftView, context: Context) {
       }
}
 

Ответ №1:

Вам нужно создать представление UIKit внутри makeUIView и через привязку передавать только зависимые данные. Это изменение привязки при изменении связанного состояния — источника истины — updateUIView вызывает вызовы , в которых вы должны обновить свое представление UIKit.

Здесь приведен только упрощенный демонстрационный эскиз, чтобы показать концепцию (могут быть опечатки):

 struct SpritzUIViewRepresentable : UIViewRepresentable{
    @Binding var currentWord: SpritzSwiftWord
    @Binding var backgroundColor: UIColor
    
    func makeUIView(context: Context) -> SpritzSwiftView {
        // create and configure view here
        return SpritzSwiftView(frame: CGRect.zero) // frame does not matter here
    }

    func updateUIView(_ uiView: SpritzSwiftView, context: Context) {
       // update view properties here from bound external data
       uiView.backgroundColor = backgroundColor
       uiView.updateWord(currentWord)
    }
}
 

и кнопка теперь должна просто изменить данные модели

     VStack {
        Text("SpritzTest")
            .padding()
        SpritzUIViewRepresentable(backgroundColor: $backgroundColor, SpritzViewManager:$ssManager, currentWord: $currentWord)
           .padding()
        Button(action:
            {
                ssManager  = SpritzSwiftManager(withText: "Text try one two three", andWordPerMinute: 200)

                self.backgroundColor = .clear
                ssManager.startReading { (word, finished) in
                    if !finished {
                        self.currentWord = word
                    }
                }
            })
        {
           Text("Start")
        }
 

предполагая обновленные свойства

 @State private var currentWord = SpritzSwiftWord(word: "")
@State private var backgroundColor = UIColor.white         // whatever you want
 

резервное копирование

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

1. Идеально! Это прекрасно работает. Теперь я лучше понимаю, как это работает. Из документации совсем не ясно, что updateUIView должен содержать связанные данные, я надеюсь, что этот ответ поможет кому-нибудь в будущем.