Need help to make a customEditMode as Environment

Viewed 73

I like to re-build a customEditMode like same editMode in SwiftUI for learning purpose, I could made my code until a full error codes as possible, that was not my plan! However here is what I tried until now, need help to get this codes work. thanks

Update:

Why this Circle color does not change?

    struct ContentView: View {

    @Environment(\.customEditMode) var customEditMode
    
    var body: some View {

        CircleView()
        
        VStack {
            
            Button("active") { customEditMode?.wrappedValue = CustomEditMode.active }.padding()

            Button("inactive") { customEditMode?.wrappedValue = CustomEditMode.inactive }.padding()

            Button("none") { customEditMode?.wrappedValue = CustomEditMode.none }.padding()
            
        }
        .onChange(of: customEditMode?.wrappedValue) { newValue in
            
            if newValue == CustomEditMode.active {
                
                print("customEditMode is active!")
            }
            else if newValue == CustomEditMode.inactive {
                
                print("customEditMode is inactive!")
            }
            else if newValue == CustomEditMode.none {
                
                print("customEditMode is none!")
            }
 
        }

    }
}

struct CircleView: View {
    
    @Environment(\.customEditMode) var customEditMode
    
    var body: some View {

        Circle()
            .fill(customEditMode?.wrappedValue == CustomEditMode.active ? Color.green : Color.red)
            .frame(width: 150, height: 150, alignment: .center)

    }
}
1 Answers

If you take a closer look at the editMode:

@available(macOS, unavailable)
@available(watchOS, unavailable)
public var editMode: Binding<EditMode>?

you can see that it is in fact a Binding. That's why you access its value using wrappedValue.

You need to do the same for your CustomEditModeEnvironmentKey:

enum CustomEditMode {
    case active, inactive, none

    // optionally, if you need mapping to `Bool?`
    var boolValue: Bool? {
        switch self {
        case .active: return true
        case .inactive: return false
        case .none: return nil
        }
    }
}

struct CustomEditModeEnvironmentKey: EnvironmentKey {
    static let defaultValue: Binding<CustomEditMode>? = .constant(.none)
}

extension EnvironmentValues {
    var customEditMode: Binding<CustomEditMode>? {
        get { self[CustomEditModeEnvironmentKey] }
        set { self[CustomEditModeEnvironmentKey] = newValue }
    }
}

Here is a demo:

struct ContentView: View {
    @State private var customEditMode = CustomEditMode.none

    var body: some View {
        TestView()
            .environment(\.customEditMode, $customEditMode)
    }
}

struct TestView: View {
    @Environment(\.customEditMode) var customEditMode

    var body: some View {
        Circle()
            .fill(customEditMode?.wrappedValue == .active ? Color.green : Color.red)
            .frame(width: 150, height: 150, alignment: .center)
        VStack {
            Button("active") { customEditMode?.wrappedValue = .active }.padding()
            Button("inactive") { customEditMode?.wrappedValue = .inactive }.padding()
            Button("none") { customEditMode?.wrappedValue = .none }.padding()
        }
        .onChange(of: customEditMode?.wrappedValue) { newValue in
            print(String(describing: newValue))
        }
    }
}

enter image description here

Related