如何触发 UIViewRepresentable 的 updateUIView?

Mar*_*nte 15 swift swiftui

我正在尝试将SpritzSwift中的 uiView 实现到 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")
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

这是包装器:

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) {
       }
}
Run Code Online (Sandbox Code Playgroud)

Asp*_*eri 21

您需要在内部创建 UIKit 视图makeUIView,并通过 Binding 仅传递依赖数据。当相关状态(事实来源)发生变化时,绑定发生变化,调用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)
    }
}
Run Code Online (Sandbox Code Playgroud)

现在按钮应该只更改模型数据

    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")
        }
Run Code Online (Sandbox Code Playgroud)

假设更新属性

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

  • 完美的!这效果很好。我现在更好地理解这是如何运作的。从文档中根本不清楚 updateUIView 应该包含绑定数据,我希望这个答案能对将来的人有所帮助。 (4认同)