Learn Courses My Dashboard

Using Picker Selection in another view

Hi team,

I am trying to use the selection of a picker in another view.

I have put in some cleared code to try work out the issue as it appears to be in the SecondView preview section where I am getting an error Type ‘MainView’ has no member ‘Annually’

Any help here would be amazing.

Thanks

import SwiftUI

struct MainView: View {
    
    var frequency: Period
    @State var selectedFrequency = Period.Annually

    var body: some View {
        List {
            PeriodPicker(selection: $selectedFrequency)
        }
    }
}

struct MainView_Previews: PreviewProvider {
    static var previews: some View {
        MainView(frequency: .Annually)
    }
}

import SwiftUI

struct SecondView: View {
    var main: MainView
    
    var body: some View {
        Text("\(main.selectedFrequency.rawValue)")
    }
}

struct SecondView_Previews: PreviewProvider {
    static var previews: some View {
        SecondView(main: .Annually)
    }
}

import SwiftUI

enum Period: String, CaseIterable, Identifiable, Codable {
    case Daily
    case Weekly
    case Fortnightly
    case Monthly
    case Quarterly
    case Annually
    
    
    var name: String {
        rawValue.capitalized
    }
    var id: String {
        name
    }
}

import SwiftUI

struct PeriodView: View {
    let period: Period
    
    var body: some View {
        ZStack {
            Label(period.name, systemImage: "calendar")
                .padding(4)
        .fixedSize(horizontal: false, vertical: true)
}
}
}

struct ThemeView_Previews: PreviewProvider {
    static var previews: some View {
        PeriodView(period: .Weekly)
    }
}

import SwiftUI

struct PeriodPicker: View {
    @Binding var selection: Period
    
    var body: some View {
        Picker("Frequency", selection: $selection) {
            ForEach(Period.allCases) {
                period in
                    PeriodView(period: period)
                        .tag(period)
            }
    }
}
}

struct PeriodPicker_Previews: PreviewProvider {
    static var previews: some View {
        PeriodPicker(selection: .constant(.Weekly))
    }
}


The reason you are getting the error Type ‘MainView’ has no member ‘Annually’ is because your SecondView is expecting a value of type MainView for its main property but you are giving it .Annually, which is of type Period. So the compiler is interpreting this as you trying to call a property .Annually on MainView, and that doesn’t work because it doesn’t exist.

I don’t see any place in the code you’ve posted where SecondView is called so it’s hard to give a definitive answer without seeing how this will all be used. But…

struct SecondView: View {
    var main: MainView
    
    var body: some View {
        Text("\(main.selectedFrequency.rawValue)")
    }
}

That’s not really how SwiftUI Views are used. You don’t generally store them as a property of another View and call on their properties and methods.

Instead, assuming that SecondView will get instantiated from within MainView, you would pass in the value you want to use from the parent View. In this case, that would be the selectedFrequency.

Whether that value should be passed in as a simple let constant or as a Binding that can be changed depends on how the value will be used in the child View. Strictly going by this example, it should be a let constant, so:

struct SecondView: View {
    let frequency: Period
    
    var body: some View {
        Text("\(frequency.rawValue)")
    }
}

struct SecondView_Previews: PreviewProvider {
    static var previews: some View {
        SecondView(frequency: .Annually)
    }
}

And a separate note because I can’t resist:

    var name: String {
        rawValue.capitalized
    }

You don’t need to call .capitalized on the rawValue since all of them are already capitalized (e.g., Annually, Quaterly, Monthly, etc.).

Thanks for that, not sure this will help resolve my issue.

In MainView if I select Annually in the picker I want to show Annually in the SecondView.

Calling Period won’t achieve that will it?

Thanks

You aren’t calling Period. You are passing a value of type Period into SecondView.

If you want to show .Annually in SecondView, you need to pass in a Period value because .Annually is a case of the Period enum. You don’t pass in MainView, which is a View, not a Period.

So something like this:

struct MainView: View {
    @State private var selectedFrequency = Period.Annually

    var body: some View {
        SecondView(frequency: selectedFrequency)
    }
}

If you wanted to be able to change the Period value in SecondView, you would need to pass a Binding to selectedFrequency instead.