Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

How do I share/bind @StateObject between SwiftUI views?

I have the following SwiftUI View "PaletteBar":

struct PaletteBar: View {

    final class State: ObservableObject {
        @Published var selectedColor: Color? = .black
        @Published var isEraserSelected = false
    }

    private enum Constants {
        static let colors: [Color] = [.black, .white, .blue, .green, .yellow, .red]
        static let eraserColor: Color = .black.opacity(0.7)
    }

    // MARK: - Properties

    @ObservedObject var state = State()

    // MARK: - Body

    var body: some View {
        HStack {
            PaletteItem(color: Constants.eraserColor, isSelected: Binding(
                get: { state.isEraserSelected },
                set: {
                    state.isEraserSelected = $0
                    state.selectedColor = $0 ? nil : state.selectedColor
                }
            ))
            .overlay { Image(systemName: "pencil.slash") }
            .foregroundColor(.white)
            .frame(maxWidth: .infinity)

            ForEach(Constants.colors, id: \.self) { color in
                PaletteItem(color: color, isSelected: Binding(
                    get: { state.selectedColor == color },
                    set: {
                        state.selectedColor = $0 ? color : nil
                        state.isEraserSelected = $0 ? false : state.isEraserSelected
                    }
                ))
                .frame(maxWidth: .infinity)
            }
        }
    }

}

This stores the state in an @ObservedObject. I would like to pass this state up the hierarchy e.g PaletteBar is a sub view of AnnotateImageToolbar:

struct AnnotateImageToolbar: View {

    final class State: ObservableObject {
        @Published var selectedColor: Color? = .black
        @Published var isEraserSelected = false
    }

    private enum Constants {
        static let spacing: CGFloat = 12.0
        static let backgroundColor: Color = .black.opacity(0.7)
        static let colorsInsets = EdgeInsets(top: 12.0, leading: 16.0, bottom: 0.0, trailing: 16.0)
        static let sliderInsets = EdgeInsets(top: 0.0, leading: 16.0, bottom: 12.0, trailing: 16.0)
        static let radius: CGFloat = 8.0
    }

    // MARK: - State

    @StateObject var state = State()

    var body: some View {
        VStack(spacing: Constants.spacing) {
            PaletteBar()
                .padding(Constants.colorsInsets)

            ZStack {
                SizeBar()
                    .foregroundColor(.gray)
                    .frame(maxHeight: 12.0)
                BrushSizeSlider()
            }
            .padding(Constants.sliderInsets)
        }
        .background(Constants.backgroundColor)
        .clipShape(RoundedCorners(radius: Constants.radius, corners: [.topLeft, .topRight]))
    }

}

Here I create an identical state object @StateObject var state = State(). Is there a way to bind the values from the state in PaletteBar to the state in AnnotateImageToolbar? Or Should I be creating a single state object and injecting it into each view?

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

>Solution :

Inject it as environment object, like

@StateObject var state = State()

var body: some View {
    VStack(spacing: Constants.spacing) {
      // ... other code
    }
    .background(...)
    .clipShape(...)
    .environmentObject(state)  // << here !!

and use it inside children:

struct PaletteBar: View {

    // MARK: - Properties

    @EnvironmentObject var state: State  // << injected by parent !!

// ...
}
Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading