您如何在类中进行双向绑定? [英] How do you make a two way binding within a class?

查看:109
本文介绍了您如何在类中进行双向绑定?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

使用@EnvironmentObject,我创建了一个从ObservableObject继承的类,并且是@Published全局变量的中心.我无法从类内部创建双向绑定.我该怎么做? $在类中不起作用,因为它仅与@State一起使用,而@State在类中不起作用.我需要双向绑定,因为当用户在屏幕上移动一个子实例时,每个子实例都必须具有屏幕位置的实时数据更改.这是我的代码:

Using @EnvironmentObject I created a class that inherits from ObservableObject and is the hub for @Published global variables. I couldn't create a two way binding from within the class though. How can I accomplish that? The $ doesn't work in classes because it only works with @State, and @State doesn't work in classes. I need two-way binding because each child instance must have real-time data change of the screen position when the user moves a child instance around the screen. Here is my code:

import SwiftUI

struct ContentView: View {
    @EnvironmentObject var settings: DataBridge
    
    var body: some View {
        ZStack {
            ForEach(self.settings.childInstances.indices , id: \.self) { index in
                self.settings.childInstances[index]
            }
            VStack {
                ForEach(self.settings.childInstanceData.indices, id: \.self) { index in
                    Text("\(index). y: \(self.settings.childInstanceData[index].height) : x: \(self.settings.childInstanceData[index].width)")
                }
            }
            .offset(y: -250)
            
        }
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

import SwiftUI

struct Child: View {
    @EnvironmentObject var settings: DataBridge
    @Binding var stateBinding: CGSize
    
    @State var isInitalDrag = true
    @State var isOnce = true
    
    @State var currentPosition: CGSize = .zero
    @State var newPosition: CGSize = .zero
    
    var body: some View {
        Circle()
            .frame(width: 50, height: 50)
            .foregroundColor(.blue)
            .offset(self.currentPosition)
            .gesture(
                DragGesture()
                    .onChanged { value in
                        
                        if self.isInitalDrag && self.isOnce {
                            
                            // Call function in DataBridge here:
                            self.settings.addChild()
                            
                            self.isOnce = false
                        }
                        
                        self.currentPosition = CGSize(
                            width: CGFloat(value.translation.width + self.newPosition.width),
                            height: CGFloat(value.translation.height + self.newPosition.height)
                        )
                        
                        self.stateBinding = self.currentPosition
                    }
                    .onEnded { value in
                        self.newPosition = self.currentPosition
                        
                        self.isOnce = true
                        self.isInitalDrag = false
                    }
            )
    }
}

struct Child_Previews: PreviewProvider {
    static var previews: some View {
        Child(stateBinding: .constant(.zero))
    }
}

class DataBridge: ObservableObject {
    @Published var childInstances: [Child] = []
    @Published var childInstanceData: [CGSize] = []
    @Published var childIndex = 0
    func addChild() {
        self.childInstanceData.append(.zero)
        
        // This where I want two-way binding with the childInstanceData array:
        self.childInstances.append(Child(stateBinding: $childInstanceData[childIndex]))
        
        self.childIndex += 1
    }
}

推荐答案

您所拥有的完全是我会做的,但是我将对Child

What you have is exactly what I would do, but instead I would use custom Binding for the Child

class DataBridge: ObservableObject {
    @Published var childInstances: [Child] = []
    @Published var childInstanceData: [CGSize] = []
    @Published var childIndex = 0
    func addChild() {
        self.childInstanceData.append(.zero)
        
        // This where I want two-way binding with the childInstanceData array:
        let child = Child(stateBinding: Binding(get: {
            return self.childInstanceData[self.childIndex]
        }, set: {
            self.childInstanceData[self.childIndex] = $0
        }))

        self.childInstances.append(child)
        
        self.childIndex += 1
    }
}

这基本上是使用自定义绑定来实现您的目标的.

This basically uses custom binding to achieve your goal.

这篇关于您如何在类中进行双向绑定?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆