Why view modifier can't take in immutable variable?

Viewed 243

I made a button modifier, the background colour should change according to if it has been clicked or not. But I get complaint that the input parameter of viewModifier is immutable.

I got error on btnBkColor of

.modifier(ActionButtonType(bkColor: btnBkColor))

The error msg:

Cannot use mutating getter on immutable value: 'self' is immutable

Here are my simplified code:

struct MyView: View {
@State private var cond = false
private lazy var btnBkColor: Color = cond ? Color.orange : Color.green
var body: some View {
              Button(action: { cond.toggle() }, label: {
              Text(cond ? "A" : "B")
  })
  .modifier(ActionButtonType(bkColor: btnBkColor))
}
}

Modifier:

struct ActionButtonType: ViewModifier {
    let bkColor: Color
    func body(content: Content) -> some View {
        content
            .background(bkColor)
    }
}

I only get but not set btnBkColor inside ViewModifier, I don't understand why can't the input parameter be immutable?

What I have tried but not help:

  • change let to var
  • add @State in front of btnBkColor
2 Answers

Use computed property. You can not use the self variable directly to the other variable.

struct MyView: View {
    @State private var cond = false
    
    private var btnBkColor: Color {
        cond ? Color.orange : Color.green
    } // <--Here
    
    var body: some View {
        Button(action: { cond.toggle() }, label: {
            Text(cond ? "A" : "B")
        })
        .modifier(ActionButtonType(bkColor: btnBkColor))
    }
}

The simplest case, and most often used in SwiftUI code, is to use state dependency inline of modifier (this will also be animatable when/if needed)

struct MyView: View {
  @State private var cond = false

  var body: some View {
      Button(action: { cond.toggle() }, label: {
         Text(cond ? "A" : "B")
      })
      .modifier(ActionButtonType(bkColor: cond ? Color.orange : Color.green))
  }
}
Related