根据选择更改选择器背景颜色

问题描述 投票:0回答:1

我有两个选择器,一个用于优先级,另一个用于选择日期。我想根据优先级选择器的选择更改两个选择器的背景,例如,如果优先级高,选择器应该是红色,中间橙色等等...... 目前我只能使用初始化程序手动设置选择器的背景颜色。 这是我的视图代码:

struct AddWunschSheetView: View {
    
    @State private var titelTextField: String = ""
    @State private var kostenTextField: String = ""
    
    @State private var sliderValue = 1.0
    @State private var amount = 0.5
    
    @State private var prioPicker = 1
    @State private var selection = 1
    
    @Environment(\.dismiss) var dismiss
    
    init() {
        UISegmentedControl.appearance().selectedSegmentTintColor = UIColor.red
        
        let attributes: [NSAttributedString.Key:Any] = [
            .foregroundColor: UIColor.white
        ]
        UISegmentedControl.appearance().setTitleTextAttributes(attributes, for: .selected)
    }
    
    var body: some View {
        NavigationStack {
            Form {
                Section("Artikeldetails") {
                    TextField("", text: $titelTextField, prompt: Text("Titel des Artikels"))
                }
                
                Section("Priority") {
                    Picker("", selection: $prioPicker) {
                        Text("Dringend").tag(1)
                        Text("Hoch").tag(2)
                        Text("Mittel").tag(3)
                        Text("Niedrig").tag(4)
                    }
                    .pickerStyle(.segmented)
                }
                
                Picker("", selection: $selection) {
                    Text("Tag").tag(1)
                    Text("Woche").tag(2)
                    Text("Monat").tag(3)
                }
                .pickerStyle(.segmented)
                
                if selection == 1 {
                    Slider(value: $sliderValue, in: 1...31, step: 1.0, minimumValueLabel: Text("1"), maximumValueLabel: Text("31"), label: {})
                        .padding(.horizontal)
                } else if selection == 2 {
                    Slider(value: $sliderValue, in: 1...52, step: 1.0, minimumValueLabel: Text("1"), maximumValueLabel: Text("52"), label: {})
                        .padding(.horizontal)
                } else if selection == 3 {
                    Slider(value: $sliderValue, in: 1...12, step: 1.0, minimumValueLabel: Text("1"), maximumValueLabel: Text("12"), label: {})
                        .padding(.horizontal)
                }

                HStack {
                    Spacer()
                    Text( String(format: "%.0f", sliderValue))
                    if selection == 1 {
                        Text("Tage bis zum Ereigniss")
                    } else if selection == 2 {
                        Text("Wochen bis zum Ereigniss")
                    } else if selection == 3 {
                        Text("Monate bis zum Ereigniss")
                    }
                    Spacer()
                }
                
                HStack {
                    VStack {
                        Text("Kosten")
                            .bold()
                        TextField("", text: $kostenTextField, prompt: Text("0€"))
                            .keyboardType(.numberPad)
                            .padding(.top)
                    }
                    Spacer()
                    
                    if prioPicker == 1 {
                        Gauge(value: amount) {
                            Text("50%")
                        }
                        .gaugeStyle(.accessoryCircularCapacity)
                        .tint(.red)
                    } else if prioPicker == 2 {
                        Gauge(value: amount) {
                            Text("50%")
                        }
                        .gaugeStyle(.accessoryCircularCapacity)
                        .tint(.orange)
                    } else if prioPicker == 3 {
                        Gauge(value: amount) {
                            Text("50%")
                        }
                        .gaugeStyle(.accessoryCircularCapacity)
                        .tint(.blue)
                    } else if prioPicker == 4 {
                        Gauge(value: amount) {
                            Text("50%")
                        }
                        .gaugeStyle(.accessoryCircularCapacity)
                        .tint(.green)
                    }
                    
                }
                .padding(.horizontal)
            }
            .navigationTitle("Neuen Artikel hinzufügen")
            .toolbar {
                ToolbarItem(placement: .topBarTrailing) {
                    Button("Save") {
                        dismiss()
                    }
                }
            }
        }
    }
}

用户界面如下所示:

我已经尝试过使用 if 语句自定义 init,我尝试过自定义部分、选择器...... 我什至不确定这是否可能。

swiftui picker
1个回答
0
投票

正如您所发现的,向分段的

Picker
添加样式很困难。但是,您可以做的是使用与 iOS 中的分段选择器 - 处理已选定项目上的点击(这是我的答案)的答案中所示相同的技术:

  • 不要在背景中显示颜色,而是将其显示为前景中的叠加层
  • 所选项目的标签也需要显示
  • 使用
    .matchedGeometryEffect
  • 将覆盖层移动到位
  • 隐藏占位符用作
    .matchedGeometryEffect
    的源。

.matchedGeometryEffect
需要命名空间:

@Namespace private var ns

不再需要您之前使用旧版 UI 调用的

init

//    init() {
//        UISegmentedControl.appearance().selectedSegmentTintColor = UIColor.red
//
//        let attributes: [NSAttributedString.Key:Any] = [
//            .foregroundColor: UIColor.white
//        ]
//        UISegmentedControl.appearance().setTitleTextAttributes(attributes, for: .selected)
//    }

我建议为您的优先级创建一个枚举,例如:

enum Priority: CaseIterable {
    case dringend
    case hoch
    case mittel
    case niedrig

    var asString: String {
        "\(self)".capitalized
    }

    var color: Color {
        switch self {
        case .dringend: .red
        case .hoch: .orange
        case .mittel: .blue
        case .niedrig: .green
        }
    }
}

此枚举应用于保存优先级选择的状态变量:

@State private var prioPicker = Priority.dringend

然后可以按如下方式组装

Picker

Section("Priority") {
    Picker("", selection: $prioPicker) {
        ForEach(Priority.allCases, id: \.self) { priority in
            Text(priority.asString)
        }
    }
    .pickerStyle(.segmented)
    .background {

        // A row of placeholders
        HStack(spacing: 0) {
            ForEach(Priority.allCases, id: \.self) { priority in
                Color.clear
                    .matchedGeometryEffect(id: priority, in: ns, isSource: true)
            }
        }
    }
    .overlay {
        ZStack {
            Rectangle()
                .fill(prioPicker.color)
            Text(prioPicker.asString)
                .font(.footnote)
                .fontWeight(.semibold)
                .foregroundStyle(.white)
        }
        .matchedGeometryEffect(id: prioPicker, in: ns, isSource: false)
        .clipShape(RoundedRectangle(cornerRadius: 7))
        .animation(.easeOut(duration: 0.2), value: prioPicker)
    }
}

Gauge
也可以简化为:

Gauge(value: amount) {
    Text("50%")
}
.gaugeStyle(.accessoryCircularCapacity)
.tint(prioPicker.color)

它的外观如下:

Animation

有趣的是,

RoundedRectangle
夹子形状会自动采用方角作为内边缘,就像您希望的那样!

© www.soinside.com 2019 - 2024. All rights reserved.