8

タイトルが示すように、ある子ビュー (A) から親ビュー (P) を介して別の子ビュー (B) にデータを渡そうとしています。

親ビューは次のようになります。

@State var rectFrame: CGRect = .zero 

var body: some View {
    childViewA(rectFrame: $rectFrame)
    childViewB()
}

どこで必要な をchildViewA取得CGRectchildViewBます。

childViewA次のようになります。

@Binding var rectFrame: CGRect

var body: some View {
    // Very long code where rectFrame is obtained and printed to console correctly
}

rectFrameに渡すにはどうすればよいchildViewBですか? との両方に正しい値を出力しているにもかかわらず、これまでに試したことはすべて に返さCGRect.zeroれます。childViewBparentViewchildViewA

に値を渡そうとするために、次のようchildViewBに書き直しました。parentView

@State var rectFrame: CGRect = .zero 

var body: some View {
    childViewA(rectFrame: $rectFrame)
    childViewB(rectFrame: $rectFrame.value)
}

childViewB次の構造を持つ:

var rectFrame: CGRect = CGRect.zero

var body: some View {

}

しかし、それはCGRect.zero毎回印刷されます。

最近試し@ObjectBindingてみましたが、苦労したので、誰かがこの特定の例で私を助けてくれたら、とても感謝しています.

class SourceRectBindings: BindableObject {
    let willChange = PassthroughSubject<Void, Never>()

    var sourceRect: CGRect = .zero {
        willSet {
            willChange.send()
        }
    }
}
4

4 に答える 4

7

このようなものにEnvironmentObjectを使用できます...

EnvironmentObjectの優れた点は、その変数の 1 つを変更するたびに、その変数が使用されているすべての場所で常に更新されることです。

注:すべての変数を更新するには、更新したいeveryViewのBindableObjectクラス/ EnvironmentObjectを確実に渡す必要があります...

SourceRectBinding:

class SourceRectBindings: BindableObject {

    /* PROTOCOL PROPERTIES */
    var willChange = PassthroughSubject<Application, Never>()

    /* Seems Like you missed the 'self' (send(self)) */
    var sourceRect: CGRect = .zero { willSet { willChange.send(self) }
}

親:

struct ParentView: view {
    @EnvironmentObject var sourceRectBindings: SourceRectBindings

    var body: some View {
        childViewA()
            .environmentObject(sourceRectBindings)
        childViewB()
            .environmentObject(sourceRectBindings)
    }
}

ChildViewA:

struct ChildViewA: view {
    @EnvironmentObject var sourceRectBindings: SourceRectBindings

    var body: some View {

        // Update your frame and the environment...
        // ...will update the variable everywhere it was used

        self.sourceRectBindings.sourceRect = CGRect(x: 0, y: 0, width: 300, height: 400)
        return Text("From ChildViewA : \(self.sourceRectBindings.sourceRect)")
    }
}

ChildViewB:

struct ChildViewB: view {
    @EnvironmentObject var sourceRectBindings: SourceRectBindings

    var body: some View {
        // This variable will always be up to date
        return Text("From ChildViewB : \(self.sourceRectBindings.sourceRect)")
    }
}

機能させるための最後のステップ

•親ビューである変数を更新したい最高のビューに移動しますが、私は通常、SceneDelegateを好みます...だから、これは私が通常行う方法です:

let sourceRectBindings = SourceRectBindings()

• 次に、同じクラスで「SceneDelegate」がルート ビューを指定する場所に移動し、EnviromentObject を通過します。

window.rootViewController = UIHostingController(
                rootView: ContentView()
                    .environmentObject(sourceRectBindings)
            )

• 最後のステップとして、5 月の親ビューに渡します。

struct ContentView : View {

    @EnvironmentObject var sourceRectBindings: SourceRectBindings

    var body: some View {
        ParentView()
            .environmentObject(sourceRectBindings)
    }
}

このようにコードを実行すると、プレビューでエラーがスローされることがわかります。これは、環境変数が渡されなかったためです。これを行うには、環境のダミーのようなインスタンスを開始するだけです:

#if DEBUG
struct ContentView_Previews : PreviewProvider {
    static var previews: some View {
        ContentView()
            .environmentObject(SourceRectBindings())
    }
}
#endif

これで、その変数を好きなように使用できます。rect 以外のものを渡したい場合は、変数を EnvironmentObject クラスに追加するだけで、アクセスして更新できます。

于 2019-07-22T07:46:19.863 に答える
0

2 人の子供の間で情報を共有するという問題を正しく理解できたことを願っています。私が取ったアプローチは、同じ状態を共有する両方の子に @Binding 変数を持たせることです。つまり、両方を $rectFrame でインスタンス化します。そうすれば、両方ともインスタンス化時の値ではなく、常に同じ値になります。

私の場合、1 つの子で更新され、別の子でリストに表示されたのは配列だったので、SwiftUI が変更に対応しました。たぶん、あなたのケースはそれほど単純ではありません。

于 2019-07-25T09:01:55.397 に答える