web-dev-qa-db-ja.com

状態が変化したときにアクションを実行するにはどうすればよいですか?

_enum SectionType: String, CaseIterable {
    case top = "Top"
    case best = "Best"
}

struct ContentView : View {
    @State private var selection: Int = 0

    var body: some View {
        SegmentedControl(selection: $selection) {
            ForEach(SectionType.allCases.identified(by: \.self)) { type in
                Text(type.rawValue).tag(type)
            }
        }
    }
}
_

_$selection_の状態が変化したときにコードを実行するにはどうすればよいですか(例:print("Selection changed to \(selection)"))?ドキュメントを調べましたが何も見つかりませんでした。

22

didSetオブザーバーは@Stateでは使用できませんが、ObservableObjectプロパティでは使用できます。

import SwiftUI
import Combine

final class SelectionStore: ObservableObject {
    var selection: SectionType = .top {
        didSet {
            print("Selection changed to \(selection)")
        }
    }

    // @Published var items = ["Jane Doe", "John Doe", "Bob"]
}

次に、次のように使用します。

import SwiftUI

enum SectionType: String, CaseIterable {
    case top = "Top"
    case best = "Best"
}

struct ContentView : View {
    @ObservedObject var store = SelectionStore()

    var body: some View {
        List {
            Picker("Selection", selection: $store.selection) {
                ForEach(FeedType.allCases, id: \.self) { type in
                    Text(type.rawValue).tag(type)
                }
            }.pickerStyle(SegmentedPickerStyle())

            // ForEach(store.items) { item in
            //     Text(item)
            // }
        }
    }
}
24

@Bindingを更新するコンポーネントがある場合の別のオプションを次に示します。これを行うのではなく:

Component(selectedValue: self.$item, ...)

あなたはこれを行うことができ、もう少し大きな制御をすることができます:

Component(selectedValue: Binding(
    get: { self.item },
    set: { (newValue) in
              self.item = newValue
              // now do whatever you need to do once this has changed
    }), ... )

このようにして、Componentが値を変更したときの検出とともに、バインディングの利点を得ることができます。

6
P. Ent

実際にはあなたの質問には答えていませんが、SegmentedControlを設定する正しい方法を次に示します(見栄えが悪いため、そのコードをコメントとして投稿したくありませんでした)。 ForEachバージョンを次のコードに置き換えます。

_ForEach(0..<SectionType.allCases.count) { index in 
    Text(SectionType.allCases[index].rawValue).tag(index)
}
_

列挙型のケースまたは文字列でさえビューにタグを付けると、ビューの動作が不十分になります。選択は機能しません。

選択が確実に機能するように、SegmentedControl宣言の後に以下を追加することもできます。

Text("Value: \(SectionType.allCases[self.selection].rawValue)")

bodyのフルバージョン:

_var body: some View {
    VStack {
        SegmentedControl(selection: self.selection) {
            ForEach(0..<SectionType.allCases.count) { index in
                Text(SectionType.allCases[index].rawValue).tag(index)
                }
            }

        Text("Value: \(SectionType.allCases[self.selection].rawValue)")
    }
}
_

あなたの質問について– didSetオブザーバーをselectionに追加しようとしましたが、ビルドしようとするとXcodeエディターがクラッシュし、「セグメンテーション違反:11」エラーが発生します。

1
Russian