swiftuiuisegmentedcontrol

Disable a segment in a SwiftUI SegmentedPickerStyle Picker?


My SwiftUI app has a segmented Picker and I want to be able to disable one or more options depending on availability of options retrieved from a network call. The View code looks something like:

    @State private var profileMetricSelection: Int = 0
    private var profileMetrics: [RVStreamMetric] = [.speed, .heartRate, .cadence, .power, .altitude]
    @State private var metricDisabled = [true, true, true, true, true]

    var body: some View {
        VStack(alignment: .leading, spacing: 2.0) {
            ...(some views)...
            Picker(selection: $profileMetricSelection, label: Text("")) {
                ForEach(0 ..< profileMetrics.count) { index in
                    Text(self.profileMetrics[index].shortName).tag(index)
                }
            }.pickerStyle(SegmentedPickerStyle())
            ...(some more views)...
        }
    }

What I want to be able to do is modify the metricDisabled array based on network data so the view redraws enabling the relevant segments. In UIKit this can be done by calls to setEnabled(_:forSegmentAt:) on the UISegmentedControl but I can't find a way of doing this with the SwiftUI Picker

I know I can resort to wrapping a UISegmentedControl in a UIViewRepresentable but before that I just wanted to check I'm not missing something...


Solution

  • Since iOS 17 you can use the modifier selectionDisabled(_:):

    VStack(alignment: .leading, spacing: 2.0) {
        // ...(some views)...
        Picker("", selection: $profileMetricSelection) {
            ForEach(Array(profileMetrics.enumerated()), id: \.offset) { index, metric in
                Text(metric.shortName)
                    .selectionDisabled(metricDisabled[index]) // 👈 here
                    .tag(index)
            }
        }
        .pickerStyle(.segmented)
        // ...(some more views)...
    }