在SwiftUI SegmentedPickerStyle选择器中禁用段?

在SwiftUI SegmentedPickerStyle选择器中禁用段?,swiftui,uisegmentedcontrol,Swiftui,Uisegmentedcontrol,我的SwiftUI应用程序有一个分段选择器,我希望能够禁用一个或多个选项,具体取决于从网络通话中检索到的选项的可用性。视图代码如下所示: @State private var profileMetricSelection: Int = 0 private var profileMetrics: [RVStreamMetric] = [.speed, .heartRate, .cadence, .power, .altitude] @State private var me

我的SwiftUI应用程序有一个分段选择器,我希望能够禁用一个或多个选项,具体取决于从网络通话中检索到的选项的可用性。视图代码如下所示:

    @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)...
        }
    }

@State private var profileMetricSelection:Int=0
私有var profileMetrics:[RVStreamMetric]=[.速度、心率、节奏、功率、高度]
@状态私有变量metricDisabled=[true,true,true,true,true]
var body:一些观点{
VStack(对齐:。前导,间距:2.0){
…(一些观点)。。。
选择器(选择:$profileMetricSelection,标签:Text(“”)){
ForEach(0..
我希望能够根据网络数据修改
metricDisabled
数组,以便视图重画相关段。在UIKit中,这可以通过调用UISegmentedControl上的
setEnabled(u:forSegmentAt:)
来完成,但我找不到使用SwiftUI选择器来实现这一点的方法


我知道我可以在UIViewRepresentable中包装一个UISegmentedControl,但在此之前,我只想检查一下我没有遗漏什么…

您可以使用这个简单的技巧

import SwiftUI

struct ContentView: View {
    @State var selection = 0
    let data = [1, 2, 3, 4, 5]
    let disabled = [2, 3] // at index 2, 3
    var body: some View {

        let binding = Binding<Int>(get: {
            self.selection
        }) { (i) in
            if self.disabled.contains(i) {} else {
                self.selection = i
            }
        }

        return VStack {
            Picker(selection: binding, label: Text("label")) {
                ForEach(0 ..< data.count) { (i) in
                    Text("\(self.data[i])")
                }
            }.pickerStyle(SegmentedPickerStyle())
            Spacer()
        }
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}
导入快捷界面
结构ContentView:View{
@状态变量选择=0
让数据=[1,2,3,4,5]
设disabled=[2,3]//在索引2,3处
var body:一些观点{
let binding=binding(获取:{
自我选择
}){(i)在
如果self.disabled.contains(i){}else{
自我选择=i
}
}
返回VStack{
选择器(选择:绑定,标签:文本(“标签”)){
ForEach(0..

也许像

ForEach(0 ..< data.count) { (i) in
    if !self.disabled.contains(i) {
        Text("\(self.data[i])")
    } else {
        Spacer()
    }
}
ForEach(0..
有助于更好地形象化

注释(基于讨论)

从用户的角度来看,选择器是一个控件,可以处于禁用/启用状态

从选择器中选择的选项不是control,而是某个值。如果您将控件列表呈现给用户,其中一些控件可能会被禁用,只是为了通知用户,与之相关的操作当前不可用(如菜单、某些按钮集合等)

我建议您只在选择器中显示可以选择的值。此值集合可以随时更新

更新

你喜欢这样的东西吗

没问题。。。(复制-粘贴-尝试-修改…)

导入快捷界面
结构数据:可识别{
让id:Int
let值:Int
禁用变量:Bool
}
结构ContentView:View{
@状态变量选择=-1
@状态变量数据=[数据(id:0,值:10,禁用:真),数据(id:1,值:20,禁用:真),数据(id:2,值:3,禁用:真),数据(id:3,值:4,禁用:真),数据(id:4,值:5,禁用:真)]
变量filteredData:[数据]{
data.filter({(item)->Bool-in
item.disabled==false
})
}
var body:一些观点{
VStack{
VStack(对齐:。前导,间距:0){
文本(“从可用中选择”)
.padding(.卧式)
.padding(.top)
HStack{
GeometryReader{中的代理
选择器(选择:self.$selection,标签:文本(“标签”)){
ForEach(self.filteredata){(项)在
文本(“\(item.value.description)”).tag(item.id)
}
}
.pickerStyle(SegmentedPickerStyle())
.frame(宽度:CGFloat(self.filteredData.count)*proxy.size.width/CGFloat(self.data.count),对齐方式:.topLeading)
垫片()
}.框架(高度:40)
}.padding()
}.背景(颜色.黄色.不透明度(0.2)).拐角半径(20)
按钮(操作:{
(0..
现在不行。使用
UISegmentedControl
。您最好基于布尔标志(因此,如果该选项不可用,请不要显示该选项)@Asperi您可以模仿它,唯一的问题是视觉样式:-(这违反了苹果的人机界面准则,行为令人困惑。这就是为什么我不建议这样做的原因(但事实上,我也尝试过类似的方法)。因此,目前如果需要段禁用功能,最好使用
UISegmentedControl
。@Asperi是的,我们需要所有这些xxxStyle协议公开。或者您可以使用间隔符作为foreach的临时替代品。感谢这两个想法,以及一些富有想象力的想法。感觉需要对SwiftUI进行重大更新,以带来功能更接近o级
import SwiftUI

struct Data: Identifiable {
    let id: Int
    let value: Int
    var disabled: Bool
}

struct ContentView: View {
    @State var selection = -1
    @State var data = [Data(id: 0, value: 10, disabled: true), Data(id: 1, value: 20, disabled: true), Data(id: 2, value: 3, disabled: true), Data(id: 3, value: 4, disabled: true), Data(id: 4, value: 5, disabled: true)]
    var filteredData: [Data] {
        data.filter({ (item) -> Bool in
            item.disabled == false
        })
    }
    var body: some View {
        VStack {
            VStack(alignment: .leading, spacing: 0) {
                Text("Select from avaialable")
                    .padding(.horizontal)
                    .padding(.top)
                HStack {
                    GeometryReader { proxy in
                        Picker(selection: self.$selection, label: Text("label")) {
                            ForEach(self.filteredData) { (item) in
                                Text("\(item.value.description)").tag(item.id)
                            }
                        }
                        .pickerStyle(SegmentedPickerStyle())
                        .frame(width: CGFloat(self.filteredData.count) * proxy.size.width / CGFloat(self.data.count), alignment: .topLeading)

                        Spacer()
                    }.frame(height: 40)
                }.padding()
            }.background(Color.yellow.opacity(0.2)).cornerRadius(20)
            Button(action: {
                (0 ..< self.data.count).forEach { (i) in
                    self.data[i].disabled = false
                }
            }) {
                Text("Enable all")
            }
            Button(action: {
                self.data[self.selection].disabled = true
                self.selection = -1
            }) {
                Text("Disable selected")
            }.disabled(selection < 0)
            Spacer()
        }
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}