简体   繁体   English

如何更改 SwiftUI 中分段拾取器的颜色外观?

[英]How can I change Color appearance of Segmented Picker in SwiftUI?

Does anyone know how to achieve this?有谁知道如何实现这一目标? I have four colors of red, green, yellow, and blue and I want my selected segment to have a background/tint color that is indicative of the color name.我有四个红色、绿色、黄色和蓝色的 colors,我希望我选择的段具有指示颜色名称的背景/色调颜色。 This is my code:这是我的代码:

let objectColors = Color.allCases

@State private var selectedColorIndex = 0

//declared inside body view

Picker("Colors", selection: $selectedColorIndex) {

        ForEach(0..<objectColors.count){ index in

            Text(self.objectColors[index].rawValue).tag(index)

        }

    }
    .pickerStyle(SegmentedPickerStyle())
    .padding(10)
    .onAppear {
        UISegmentedControl.appearance().selectedSegmentTintColor = UIColor.generateUIColor(colorIndex: selectedColorIndex)        
    }

This is the list I'm pulling from这是我要从中提取的列表

enum Color: String, CaseIterable {
    case red, yellow, green, blue
}

I've tried using onChange or onReceive (and Combine's 'Just()' for subview) instead of onAppear but they crash on playgrounds and don't work on Xcode.我尝试使用 onChange 或 onReceive(以及组合的'Just()' 用于子视图)而不是 onAppear,但它们在操场上崩溃并且在 Xcode 上不起作用。 I also saw a WWDC video on UIAction that I think will work great for updating view changes but I have no idea how to translate it.我还看到了一个关于 UIAction 的 WWDC 视频,我认为它非常适合更新视图更改,但我不知道如何翻译它。 Does anyone one have any suggestions or help, please?请问有人有什么建议或帮助吗? Thanks谢谢

Here: Since you are using enum then selected type should be enum type as well, also you had wrong naming for your custom enum .此处:由于您使用的是enum ,因此所选类型也应该是enum类型,而且您对自定义enum的命名也有误。


在此处输入图像描述

Version 1.0.0:版本 1.0.0:

struct ContentView: View {
    
    @State private var selectedColor: ColorEnum = ColorEnum.blue
    
    @State private var renderView: Bool = Bool()

    var body: some View {
        
        Group {
            
            if renderView { SegmentedPickerView(selectedColor: $selectedColor) }
            else { SegmentedPickerView(selectedColor: $selectedColor) }
            
        }
        .onChange(of: selectedColor) { _ in renderView.toggle() }
        
    }
    
}

struct SegmentedPickerView: View {
    
    @Binding var selectedColor: ColorEnum

    init(selectedColor: Binding<ColorEnum>) {
        
        self._selectedColor = selectedColor
        
        UISegmentedControl.appearance().selectedSegmentTintColor = selectedColor.wrappedValue.ColorValue
        
    }

    var body: some View {
        
        VStack {
            
            Picker("", selection: $selectedColor) {
                
                ForEach(ColorEnum.allCases, id: \.self) { item in
                    
                    Text(item.rawValue)
                    
                }
                
            }
            .pickerStyle(SegmentedPickerStyle())

            Text("You selected: " + selectedColor.rawValue)
                .bold()
                .shadow(radius: 10.0)
                .padding()

        }
        .padding()
        .background(Color.black.opacity(0.1).cornerRadius(10.0))
        .foregroundColor(Color(selectedColor.ColorValue))
        .padding()
        
    }
}

enum ColorEnum: String, CaseIterable {
    
    case red, yellow, green, blue
    
    var ColorValue: UIColor {
        
        get {
            
            switch self {
            case .red: return UIColor.red
            case .yellow: return UIColor.yellow
            case .green: return UIColor.green
            case .blue: return UIColor.blue
            }
            
        }
        
    }
}

I just updated my old Answer with new Version of it, now you can just use AdvancedSegmentedPicker in your View, and work with it like a normal SegmentedPicker with this deference that you are able to change and update all colors on SegmentedPicker , like:我刚刚用它的新版本更新了我的旧答案,现在您可以在视图中使用AdvancedSegmentedPicker ,并像使用普通SegmentedPicker一样使用它,您可以更改和更新SegmentedPicker上的所有 colors,例如:

backgroundColor背景颜色

selectedSegmentTintColor selectedSegmentTintColor

selectedSegmentForegroundColor selectedSegmentForegroundColor

normalSegmentForegroundColor normalSegmentForegroundColor


you could use like:你可以像这样使用:

AdvancedSegmentedPicker(items:selectedItem:)

Or:或者:

AdvancedSegmentedPicker(items:selectedItem:backgroundColor:selectedSegmentTintColor:selectedSegmentForegroundColor:normalSegmentForegroundColor:)

Also Notice that this AdvancedSegmentedPicker is not hard coded for just this project, as long as you gave items and selectedItem to AdvancedSegmentedPicker , you can use it in any project, and you could do your color customization as well.另请注意,此AdvancedSegmentedPicker并非仅针对此项目进行硬编码,只要您将itemsselectedItem提供给AdvancedSegmentedPicker ,您就可以在任何项目中使用它,也可以进行颜色自定义。


Version 2.0.0: 2.0.0 版:

在此处输入图像描述

import SwiftUI

struct ContentView: View {
    
    var items: [ColorEnum] = ColorEnum.allCases
    @State private var selectedItem: ColorEnum = ColorEnum.blue
    
    @State private var backgroundColor: UIColor?
    @State private var selectedSegmentTintColor: UIColor?
    @State private var selectedSegmentForegroundColor: UIColor?
    @State private var normalSegmentForegroundColor: UIColor?
    
    var body: some View {
        
        VStack(spacing: 30.0) {
            
            AdvancedSegmentedPicker(items: items, selectedItem: $selectedItem, backgroundColor: backgroundColor, selectedSegmentTintColor: selectedSegmentTintColor,
                                    selectedSegmentForegroundColor: selectedSegmentForegroundColor, normalSegmentForegroundColor: normalSegmentForegroundColor)
            
            Text("You selected: " + selectedItem.rawValue)
                .bold()
                .shadow(radius: 10.0)
                .padding()
            
            Button("update backgroundColor") {
                
                if backgroundColor == UIColor.gray { backgroundColor = nil }
                else { backgroundColor = UIColor.gray }
                
            }
            
            Button("update selectedSegmentForegroundColor") {
                
                if selectedSegmentForegroundColor == UIColor.white { selectedSegmentForegroundColor = nil }
                else { selectedSegmentForegroundColor = UIColor.white }
                
            }
            
            Button("update normalSegmentForegroundColor") {
                
                if normalSegmentForegroundColor == UIColor.white { normalSegmentForegroundColor = nil }
                else { normalSegmentForegroundColor = UIColor.white }
                
            }
            
        }
        .font(Font.body.bold())
        .onAppear() { selectedSegmentTintColor = selectedItem.ColorValue }
        .onChange(of: selectedItem) { newValue in selectedSegmentTintColor = newValue.ColorValue }
        .padding()
        .background(Color.black.opacity(0.1).cornerRadius(10.0))
        .padding()
        .statusBar(hidden: true)
        
    }
    
}

struct AdvancedSegmentedPicker<T: CustomStringConvertible & Hashable>: View {
    
    var items: [T]
    @Binding var selectedItem: T
    
    var backgroundColor: UIColor? = nil
    var selectedSegmentTintColor: UIColor? = nil
    var selectedSegmentForegroundColor: UIColor? = nil
    var normalSegmentForegroundColor: UIColor? = nil
    
    @State private var renderView: Bool = Bool()
    
    var body: some View {
        
        return Group {
            
            if renderView { SegmentedPickerView(items: items, selectedItem: $selectedItem, backgroundColor: backgroundColor, selectedSegmentTintColor: selectedSegmentTintColor,
                                                selectedSegmentForegroundColor: selectedSegmentForegroundColor, normalSegmentForegroundColor: normalSegmentForegroundColor) }
            else { SegmentedPickerView(items: items, selectedItem: $selectedItem, backgroundColor: backgroundColor, selectedSegmentTintColor: selectedSegmentTintColor,
                                       selectedSegmentForegroundColor: selectedSegmentForegroundColor, normalSegmentForegroundColor: normalSegmentForegroundColor) }
            
            
        }
        .onChange(of: backgroundColor) { _ in renderView.toggle() }
        .onChange(of: selectedSegmentTintColor) { _ in renderView.toggle() }
        .onChange(of: selectedSegmentForegroundColor) { _ in renderView.toggle() }
        .onChange(of: normalSegmentForegroundColor) { _ in renderView.toggle() }
        
    }
    
}

private struct SegmentedPickerView<T: CustomStringConvertible & Hashable>: View {
    
    var items: [T]
    @Binding var selectedItem: T
    
    init(items: [T], selectedItem: Binding<T>, backgroundColor: UIColor? = nil,
         selectedSegmentTintColor: UIColor? = nil, selectedSegmentForegroundColor: UIColor? = nil, normalSegmentForegroundColor: UIColor? = nil) {
        
        self.items = items
        self._selectedItem = selectedItem
        
        UISegmentedControl.appearance().backgroundColor = backgroundColor
        UISegmentedControl.appearance().selectedSegmentTintColor = selectedSegmentTintColor
        
        if let unwrappedSelectedSegmentForegroundColor: UIColor = selectedSegmentForegroundColor {
            UISegmentedControl.appearance().setTitleTextAttributes([.foregroundColor: unwrappedSelectedSegmentForegroundColor], for: .selected)
        }
        else {
            UISegmentedControl.appearance().setTitleTextAttributes([.foregroundColor: UIColor.label], for: .selected)
        }
        
        if let unwrappedNormalSegmentForegroundColor: UIColor = normalSegmentForegroundColor {
            UISegmentedControl.appearance().setTitleTextAttributes([.foregroundColor: unwrappedNormalSegmentForegroundColor], for: .normal)
        }
        else {
            UISegmentedControl.appearance().setTitleTextAttributes([.foregroundColor: UIColor.label], for: .normal)
        }
        
    }
    
    var body: some View {
        
        Picker("", selection: $selectedItem) {
            
            ForEach(items, id: \.self) { item in
                
                Text(String(describing: item))
                
            }
            
        }
        .pickerStyle(SegmentedPickerStyle())
        
    }
    
}

enum ColorEnum: String, CaseIterable, CustomStringConvertible { case red, yellow, green, blue
    
    var ColorValue: UIColor {
        
        get {
            
            switch self {
            case .red: return UIColor.red
            case .yellow: return UIColor.yellow
            case .green: return UIColor.green
            case .blue: return UIColor.blue
            }
            
        }
        
    }
    
    var description: String {
        
        get { return self.rawValue }
        
    }
    
}

Here is the simple version of what you need.这是您需要的简单版本。 This answer uses SwiftUI-Introspect to "Introspect underlying UIKit components from SwiftUI".这个答案使用SwiftUI-Introspect来“自省来自 SwiftUI 的底层 UIKit 组件”。

In addition, instead of UISegmentedControl.appearance() which is app-wide for all UISegmentedControl s, this only affects this specific one which can be a lot more useful.此外,与适用于所有UISegmentedControl的应用程序范围内的UISegmentedControl.appearance()不同,这只会影响这个特定的,这可能会更有用。

Here is the working code:这是工作代码:

struct ContentView: View {
    
    let objectColors = SegmentColor.allCases
    @State private var selectedColor = SegmentColor.red
    
    var body: some View {
        Picker("Colors", selection: $selectedColor) {
            ForEach(objectColors) { color in
                Text(color.rawValue).tag(color)
            }
        }
        .introspectSegmentedControl { segmentedControl in
            segmentedControl.selectedSegmentTintColor = selectedColor.color
        }
        .pickerStyle(SegmentedPickerStyle())
        .padding(10)
        .onChange(of: selectedColor) { _ in }
    }
}


enum SegmentColor: String, CaseIterable, Identifiable {
    case red, yellow, green, blue
    
    var id: String { rawValue }
    
    var color: UIColor {
        switch self {
        case .red:      return .red
        case .yellow:   return .yellow
        case .green:    return .green
        case .blue:     return .blue
        }
    }
}

Result:结果:

结果

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM