`XUIView`中的`Binding<Bool>`为什么看不到更新后的值?

huangapple go评论59阅读模式
英文:

Why does the `Binding<Bool>` in XUIView does not see the updated value?

问题

The code you provided is in Swift and contains technical details related to SwiftUI and UIKit integration. Here's a translation of the code comments and some key parts:

为什么在`XUIView`中的`Binding&lt;Bool&gt;`看不到更新后的值?

我有一个`SwiftUI``XView`,它包装了一个`XUIView`。在`XUIView`中,我有一个`Binding&lt;Bool&gt;`,它是使用`XView``@Binding...`初始化的。在`XUIView`中,我有一个`UIButton`,我可以使用`XUIView`中的“Binding”属性来切换`customFlag`。这在`SwiftUI`视图中很好地传播,因为`Text`正确更新。但是,`UIButton`的标题没有正确更新。`XUIView._update`方法无法“看到”新值。

我在这里漏掉了什么?

我是否需要在`updateUIView`方法中分配`customFlag`以使其工作?

带有一些打印调用以查看发生了什么的示例代码:

// 这里是示例代码,包括一些打印调用以查看发生的情况。

Please note that the translation retains the technical terms and code structure, but the code itself is unchanged. If you have any specific questions about the code or need further assistance, please let me know.

英文:

Why does the Binding&lt;Bool&gt; in XUIView does not see the updated value?

I have a SwiftUI XView which wraps an XUIView. In the XUIView I have a Binding&lt;Bool&gt;, which is initialised with the @Binding... of the XView. In the XUIView I have a UIButton with which I toggle the customFlag using the "Binding" property in XUIView. That propagates nicely into the SwiftUI View, as the Text updates properly. However, the UIButton's title is not updated properly. The XUIView._update method does not "see" the new value.

What am I missing here?

Do I have to assign the customFlag in the updateUIView method to make that work?

Sample code with some print calls to see what's going on:

import SwiftUI

struct UIKitBindingView: View {
    @State private var customFlag: Bool = false
    var body: some View {
        VStack {
            Text(&quot;customFlag: \(customFlag ? &quot;ON&quot; : &quot;OFF&quot;)&quot;)
            XView(customFlag: $customFlag)
                .frame(width: 200, height: 100)
        }
    }
}

struct UIKitBindingView_Previews: PreviewProvider {
    static var previews: some View {
        UIKitBindingView()
    }
}

struct XView: UIViewRepresentable {
    typealias UIViewType = XUIView
    typealias Context = UIViewRepresentableContext&lt;XView&gt;
    @Binding var customFlag: Bool
    
    init(customFlag: Binding&lt;Bool&gt;) {
        self._customFlag = customFlag
    }

    func makeUIView(context: Context) -&gt; XUIView {
        Swift.print(&quot;XView: \(#function)&quot;)
        let v = XUIView(frame: .zero, customFlag: $customFlag)
        return v
    }

    func updateUIView(_ uiView: XUIView, context: Context) {
        Swift.print(&quot;XView: \(#function)&quot;)
        // uiView.customFlag = $customFlag
        Swift.print(&quot;XView: \(#function): customFlag: \(customFlag) \n--\($customFlag)&quot;)
        uiView._update()
    }
}

class XUIView: UIView {
    weak var button: UIButton?
    var customFlag: Binding&lt;Bool&gt;
    
    init(frame: CGRect, customFlag: Binding&lt;Bool&gt;) {
        self.customFlag = customFlag
        super.init(frame: frame)
        Swift.print(&quot;XUIView: \(#function)&quot;)
        _configure()
    }
    
    required init?(coder: NSCoder) {
        self.customFlag = Binding(get: { true }, set: { v, t in })
        super.init(coder: coder)
        Swift.print(&quot;XUIView: \(#function)&quot;)
        _configure()
    }
    
    deinit {
        Swift.print(&quot;XUIView: \(#function)&quot;)
    }
    
    func _update() {
        Swift.print(&quot;XUIView: \(#function): \(customFlag.wrappedValue)\n--\(customFlag)&quot;)
        button?.setTitle(&quot;BUTTON:&quot; + (customFlag.wrappedValue ? &quot;ON&quot; : &quot;OFF&quot;), for: .normal)
    }
    
    private func _configure() {
        backgroundColor = .yellow
        let b = UIButton()
        button = b
        self.addSubview(b)
        b.translatesAutoresizingMaskIntoConstraints = false
        let cons = [
            self.centerXAnchor.constraint(equalTo: b.centerXAnchor),
            self.centerYAnchor.constraint(equalTo: b.centerYAnchor),
        ]
        NSLayoutConstraint.activate(cons)
        b.setTitleColor(.systemBlue, for: .normal)
        b.addAction(UIAction(handler: { action in
            Swift.print(&quot;XUIView: \(#function): button action ***&quot;)
            self.customFlag.wrappedValue.toggle()
        }), for: .touchUpInside)
        _update()
    }
}

Console output after tapping the button:

XUIView: __preview___configure(): button action ***
XView: __preview__updateUIView(_:context:)
XView: __preview__updateUIView(_:context:): customFlag: true 
--Binding&lt;Bool&gt;(transaction: SwiftUI.Transaction(plist: []), location: SwiftUI.LocationBox&lt;SwiftUI.Binding&lt;Swift.Bool&gt;.(unknown context at $10594f2e0).ScopedLocation&gt;, _value: true)
XUIView: __preview___update(): false
--Binding&lt;Bool&gt;(transaction: SwiftUI.Transaction(plist: []), location: SwiftUI.LocationBox&lt;SwiftUI.Binding&lt;Swift.Bool&gt;.(unknown context at $10594f2e0).ScopedLocation&gt;, _value: false)

答案1

得分: 1

Binding&lt;Bool&gt; 作为字面量并未记录为 Binding 的已记录用法。

Binding 应该作为 @Binding 属性包装器使用。

https://developer.apple.com/documentation/swiftui/binding

还要注意,Binding 符合 DynamicProperty,因此它应仅在符合 DynamicPropertyViewstruct 中使用。

在重新计算视图主体之前,视图为这些属性提供值。

您可以使用 updateUIView 从 SwiftUI 通信到 UIKit,从 UIKit 到 SwiftUI 可以使用完成处理程序、共享的真相源、委托等。

英文:

Binding&lt;Bool&gt; as a literal isn’t a documented used of Binding.

Binding should be used as an @Binding property wrapper.

https://developer.apple.com/documentation/swiftui/binding

It is also important to note that Binding conforms to DynamicProperty therefore it should only be used in a View or a struct that also conforms to DynamicProperty.

> The view gives values to these properties prior to recomputing the view’s body.

You can communicate from SwiftUI to UIKit using updateUIView and from UIKit to SwiftUI using completion handlers, a shared source of truth, a delegate, etc.

答案2

得分: 0

请参考以下翻译:

将 XUIView 的 _update() 调用(删除该方法)替换为直接在 updateUIView(_ uiView: XUIView, context: Context) 中进行更新:

func updateUIView(_ uiView: XUIView, context: Context) {
    uiView.button?.setTitle("BUTTON:" + ($customFlag.wrappedValue ? "ON" : "OFF"), for: .normal)
}
英文:

Instead of calling the _update() of the XUIView (remove that method), make the update directly in the updateUIView(_ uiView: XUIView, context: Context):

func updateUIView(_ uiView: XUIView, context: Context) {
        uiView.button?.setTitle(&quot;BUTTON:&quot; + ($customFlag.wrappedValue ? &quot;ON&quot; : &quot;OFF&quot;), for: .normal)
}

答案3

得分: 0

你忘记了用新的绑定值更新UIView,例如:

func updateUIView(_ uiView: XUIView, context: Context) {
    ...
    uiView.customFlag = _customFlag
    ...
}

请注意,仅仅传递绑定是有点懒惰的做法。最好是设置你自己的闭包。绑定基本上是一对获取和设置闭包,但你的协调器只关心一个设置闭包,所以可以创建一个didChangeCustomFlag并传递一个设置可表示对象绑定的闭包。请参考Fruta的PaymentButton.swift以获取此模式的示例。

英文:

You forgot to update the UIView with the new binding value, e.g.

func updateUIView(_ uiView: XUIView, context: Context) {
    ...
    uiView.customFlag = _customFlag
    ...
}

Note it is a little bit lazy to just pass the binding along. It would be better to set your own closure. Binding is basically a pair of get and set closures, but your coordinator is only interested in a set closure, so could just create a didChangeCustomFlag and pass a closure that sets the representable's binding. See Fruta's PaymentButton.swift for an example of this pattern.

答案4

得分: 0

我认为问题出在 Binding 类型的不正确使用,XUIView 中的 BindingBool> 无法看到更改后的值。在初始化自定义标志时,需要将 XUIView 更改为 'self.$_customFlag'。

let v = XUIView(frame: .zero, customFlag: self.$_customFlag)

在 updateUIView 函数中,可以删除有关更新绑定变量的注释行。

uiView.customFlag = $_customFlag
英文:

I think the issue is the Binding type was used improperly, the BindingBool> in the XUIView was unable to see the changed value. You need to change the XUIView when initializing the custom flag you need to declare it as 'self.$_customFlag'.

func makeUIView(context: Context) -&gt; XUIView {
        Swift.print(&quot;XView: \(#function)&quot;)
        let v = XUIView(frame: .zero, customFlag: self.$customFlag)
        return v
}

also in the updateUIView function, you can remove the comment line for updating the binding variable.

uiView.customFlag = $customFlag

huangapple
  • 本文由 发表于 2023年5月21日 16:29:32
  • 转载请务必保留本文链接:https://go.coder-hub.com/76298953.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定