Home > Back-end >  Make string and color bindable
Make string and color bindable

Time:03-17

I have some code like the following where I want to update a string and a color through SwiftUI's binding but I get these errors:

Initializer 'init(_:)' requires that 'Binding' conform to 'StringProtocol'

Cannot convert value of type 'Binding' to expected argument type 'Color?'

import SwiftUI

struct PasswordStrengthIndicator: View {
    private let segment = RoundedRectangle(cornerRadius: CGFloat(4))

    @State private var segmentColor = Color.gray
    @State private var hintText = ""

    var body: some View {
       VStack {
           segment
               .foregroundColor($segmentColor)
           Text($hintText)
       }
       .onAppear(perform: onAppear)
    }

    func onAppear() {
       segmentColor = Color.red
       hintText = "Enter password!"
    }
}

If I remove the $ binding indicator I get no errors but text and color does not get updated. How do I fix these issues in SwiftUI 2 without overcomplicating the code?

UPDATE:

Above code works but it does not work if the text/color change is done in a method called from a parent view, e.g.:

    func onAppear() {
    }

    // Called from parent view.
    func updateStrengthIndication() {
       segmentColor = Color.red
       hintText = "Enter password!"
    }

CodePudding user response:

Ok an alternative would be to create an extra View Model for your PasswordStrengthIndicator View which you could then wrap in the View Model of your parent view.

// MARK: - Parent View
class ParentViewModel: ObservableObject {
    @Published var childViewModel = PasswordStrengthIndicatorViewModel()
 
    func updateBtnDidTab() {
        childViewModel.updateIndicator()
    }
}

struct ContentView: View {
    @StateObject var parentVM = ParentViewModel()
    
    var body: some View {
        VStack {
            PasswordStrengthIndicator(
                viewModel: parentVM.childViewModel
            )
            
            Button("Change", action: parentVM.updateBtnDidTab)
        }
        
    }
}

// MARK: - Child View
class PasswordStrengthIndicatorViewModel: ObservableObject {
    @Published private(set) var segmentColor = Color.gray
    @Published private(set) var hintText = ""
    
    func updateIndicator() {
        segmentColor = Color.green
        hintText = "asdf"
    }
}

struct PasswordStrengthIndicator: View {
    @ObservedObject var viewModel: PasswordStrengthIndicatorViewModel
    
    private let segment = RoundedRectangle(cornerRadius: CGFloat(4))

    var body: some View {
       VStack {
           segment
               .foregroundColor(viewModel.segmentColor)
           Text(viewModel.hintText)
       }
    }
}

Edit:
Displaying a preview for PasswordStrengthIndicatorViewModel:

struct PasswordStrengthIndicator_Previews: PreviewProvider {
    static var previews: some View {
        PasswordStrengthIndicator(
            viewModel: PasswordStrengthIndicatorViewModel()
        )
    }
}
  • Related