[英]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
的命名也有误。
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并非仅针对此项目进行硬编码,只要您将
items
和selectedItem
提供给AdvancedSegmentedPicker ,您就可以在任何项目中使用它,也可以进行颜色自定义。
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.