TEAM LICENSES: Save money and learn new skills through a Hacking with Swift+ team license >>

Toggle with variable isOn parameter

Forums > Swift

@VRK  

At the moment I try to make the settings for my App. For that I use toggles that change the UserDefaults, but my problem is, that I cant figure out, how i can make the isOn parameter inside the Toggle variable. I created a "DataType" called "settingItem" which includes defirent properties like the name, the icon and the title of the UserDefaults key. The Toggles on the settings page are inside a List. That's why the isOn parameter should be represented by a variable.

struct SettingsView: View {
    @State var settingsList:[SettingItem] = [SettingItem]()
    var dataService = DataService()
    @AppStorage("darkMode") var darkMode = false
    let userdefault = UserDefaults.standard

    var body: some View {
        NavigationStack {
            VStack {
                HStack {
                    Spacer()
                    Image(systemName: "person.circle")
                        .resizable()
                        .scaledToFit()
                        .frame(width: 90, height: 90)
                    Spacer()
                    Text("Max Mustermann")
                    Spacer()
                }
                .frame(width: 300, height: 120)
                .background(Color.gray.opacity(0.2))
                .clipShape(RoundedRectangle(cornerRadius: 10, style: .continuous))
                NavigationStack {
                    List(settingsList){ item in
                        HStack{
                            Image(systemName: item.iconName)
                            Toggle(item.name, isOn: $(item.settingKey))
                        }

                    }
                    .clipShape(RoundedRectangle(cornerRadius: 10, style: .continuous))
                }
            }
            .onAppear(perform: {
                settingsList = dataService.getSettings()
            })
        }
        .colorScheme(darkMode ? .dark : .light)
    }
}

2      

This syntax doesn't look correct:

Toggle(item.name, isOn: $(item.settingKey))

The dollar sign tells SwiftUI that you want to read and write to a variable in both directions. That is, you want to initially set the Toggle to false, but maybe your user will change the variable in the Toggle object.

This looks like you're telling SwiftUI the entire chained variable (item and settingKey) is the binding. Instead, the only thing you want to really change is settingKey ?

You need to let SwiftUI know which part is bound.

Try:

Toggle(item.name, isOn: $item.settingsKey)

2      

@VRK  

First, thanks for your reply. Yes I only want to change the value of the UserDefault associated with that settingKey.

I tried Toggle(item.name, isOn: $item.settingsKey) but it results in an Error

Cannot find '$item' in scope

Do you have an idea how to solve this?

1      

Here's something I tried. Hope this leads you to your solution.

// Important concept!
// Break your BIG problem into several smaller, solveable problems
struct SettingItem: Identifiable {
    var id      = UUID().uuidString // unique it
    var title   = "Use FaceID"
    var isOn    = false
    var icon    = "faceid"
}

// Break your BIG problem into smaller, solvable problems
struct OptionRowView: View {
    @Binding var option: SettingItem // <-- 🐤 pass in a setting item

    var body: some View {
        // 🐤 Because option is a binding, the changes made
        // 🐤 in this view are passed back to the originator.
        Toggle( option.title, systemImage: option.icon, isOn: $option.isOn)
            .padding(.horizontal)
    }
}

// Create a specialized view.
// This view is useful for debugging.
struct DebuggingView: View {
    var settings: [SettingItem]
    var body: some View {
        Divider() // ---------------- Show state for debugging ------------
        VStack(alignment: .leading) {
            ForEach(settings) { setting in
                Text(setting.description).font(.title2)
            }
        }
        Spacer(); Spacer()
    }
}

// Keep your views small and concise.
struct SettingsView: View {
    @State var applicationSettings = SettingItem.testSettings

    var body: some View {
        VStack {
            Spacer()
            Text("Settings Example").font(.largeTitle)
            ForEach($applicationSettings){ setting in
                OptionRowView(option: setting) // <-- 🐤 Send in ONE setting item
            }
            Spacer()
            // This is a smaller, solvable problem >> Show Current State <<
            DebuggingView(settings: applicationSettings)
        }
    }
}

// Sample Data
extension SettingItem {
    static var testSettings = [
        SettingItem(title: "2 Factor Authorization", icon: "link"),
        SettingItem(title: "Use ApplePay",           icon: "creditcard.and.123"),
        SettingItem() // default
    ]

    var description: String {
        (self.isOn ? "✅ " : "❌ " ) + self.title + " is" + (self.isOn ? " on." : " off.")
    }
}

Teach the Duck how to Code

If you're having a bit o'trouble with a concept. Tell the duck! If you comment your code, then tell the duck what you're attempting to do, you often rephrase your solution in simpler terms.

Try the rubber duck method to peel back the uncertainty and try to focus on what may be the root of the problem.

See -> Rubber Ducks 🐤 Teach Swift

Keep Coding!

2      

Hacking with Swift is sponsored by Blaze.

SPONSORED Still waiting on your CI build? Speed it up ~3x with Blaze - change one line, pay less, keep your existing GitHub workflows. First 25 HWS readers to use code HACKING at checkout get 50% off the first year. Try it now for free!

Reserve your spot now

Sponsor Hacking with Swift and reach the world's largest Swift community!

Reply to this topic…

You need to create an account or log in to reply.

All interactions here are governed by our code of conduct.

 
Unknown user

You are not logged in

Log in or create account
 

Link copied to your pasteboard.