【发布时间】:2020-03-22 02:01:00
【问题描述】:
在 SwiftUI 中,我尝试使用按钮在 UIViewControllerRepresentable 中实现文本更改,但可能缺少关于绑定的关键概念。
在 SwiftUI 中:
struct MainView: View {
@State private var textHere = "Set up text"
var body: some View {
return VStack{
DisplayView(text: $textHere)
Button(action:{
self.textHere = "Button update text"
}) {
HStack {
Text("Change the text by clicking")
.background(Color.white)
}
}
.background(Color.blue)
}
}
}
然后我有一个 UIViewControllerRepresentable:
struct DisplayView: UIViewControllerRepresentable {
@Binding var text: String
func makeUIViewController(context: UIViewControllerRepresentableContext< DisplayView >) -> UIViewController {
let controller = DisplayViewController()
controller.text = text
return controller
}
func updateUIViewController(_ uiViewController: UIViewController, context: UIViewControllerRepresentableContext< DisplayView >) {
let controller = DisplayViewController()
controller.text = text
controller.updateText()
}
}
我的视图控制器:
class CameraViewController : UIViewController {
var text = "Hello"
var textViewTest = UILabel()
func updateText(){
print("update text " + text)
self.textViewTest = UILabel(frame: CGRect(x: 40.0, y: 120.0, width: 250.0, height: 100.0))
...
self.textViewTest.text = text
}
override func viewDidLoad() {
super.viewDidLoad()
self.textViewTest = UILabel(frame: CGRect(x: 40.0, y: 120.0, width: 250.0, height: 100.0))
...
self.textViewTest.text = text
view.addSubview(self.textViewTest)
}
}
我在 updateText() 函数中尝试了一些变体。
数据正在通过按钮单击传递:
- “按钮更新文本”传入UIViewControllerRepresentable的updateUIViewController方法中
- “按钮更新文本”被传递到 UIViewController
- “按钮更新文本”传入UIViewController的viewDidLoad
但是传递的值不会显示为标签上的更改。
似乎有可能在 ViewController 中进行了更新,但 SwiftUI 视图没有更新?
编辑:
This article 将我指向“包装”UIRepresentable 的方向。这是新版本:
struct DisplayView: UIViewControllerRepresentable {
typealias UIViewControllerType = CameraViewController
var text: String?
func makeUIViewController(context: UIViewControllerRepresentableContext< DisplayView >) -> CameraViewController {
print("view called")
return CameraViewController()
}
func updateUIViewController(_ cameraViewController: CameraViewController, context: UIViewControllerRepresentableContext< DisplayView >) {
print("View updated")
cameraViewController.text = text
}
}
并且 ViewController 已经更新:
final class CameraViewController : UIViewController {
var text: String? {
didSet {
updateController()
}
}
private var ccmeraViewController: CameraViewController?
func updateController(){
let textViewTest = UILabel(frame: CGRect(x: 40.0, y: 120.0, width: 250.0, height: 100.0))
guard let text = text else { return }
textViewTest.center = self.view.center
textViewTest.textAlignment = NSTextAlignment.justified
textViewTest.textColor = UIColor.blue
textViewTest.backgroundColor = UIColor.lightGray
textViewTest.text = text
view.addSubview(textViewTest)
}
override func viewDidLoad() {
super.viewDidLoad()
//updateController()
}
一切都很好!我们现在可以正确地将一个字符串值从 SwiftUI 传递给 ViewController 并更新标签。
但是,当您第一次打开页面时,makeUIViewController 和 updateUIViewController 都会被调用,因此标签的两个实例会彼此重叠。
所以最后一步是弄清楚如何只显示一次 UILabel。
更新 3 和部分解决方案
具有解决方案can be found here 的最小存储库。
答案是正确的,你需要添加@Binding。然而,有趣的是,将 String 绑定到显示标签的 ViewController 会导致视图中出现两个标签实例。
通过将 UILabel 从 SwiftUI 绑定到 UIViewControllerRepresentable 解决了这个问题,但是当 String 值更新时标签会改变位置。
我不清楚:a)为什么 UIViewControllerRepresentable 会收到两个更新视图的请求,或者 b)为什么 UILabel 会改变位置。
同样,从 SwiftUI 绑定 UILabel 也没有多大意义。这是为了测试嵌入 ViewController 并使用它们来显示标签并不是您真正想要做的,但是为什么会发生这些问题并没有多大意义。
【问题讨论】: