2

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
Sunderam Dubey
  • 1
  • 11
  • 20
  • 40
Neocoleoidea
  • 133
  • 1
  • 7

2 Answers2

2

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))
    }
}
Raja Kishan
  • 16,767
  • 2
  • 26
  • 52
  • With your 2nd solution, `btnBkColor` won't be updated when `cond` is updated. – Dávid Pásztor Feb 22 '21 at 09:49
  • @DávidPásztor. Oh yes. – Raja Kishan Feb 22 '21 at 09:52
  • Hi, it's cool how you declare btnBkColor, I have tried private var btnBkColor: Color = (cond ? Color.orange : Color.green) but get the error of "Cannot use instance member 'cond' within property initializer; property initializers run before 'self' is available" it works with your syntax ! – Neocoleoidea Feb 22 '21 at 12:51
  • Use curly bracket and remove equal to sign : ``` private var btnBkColor: Color { cond ? Color.orange : Color.green }``` – Raja Kishan Feb 22 '21 at 12:55
2

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))
  }
}
Asperi
  • 228,894
  • 20
  • 464
  • 690