如何在SwiftUI分段选择器中更改所选段的颜色

58

我希望能够设置SwiftUI分段选择器中选定的片段颜色,并将文本颜色更改为白色。

我尝试过使用选择器视图的修饰符以及从外观代理修改色调颜色。 不幸的是,它们都似乎不起作用。


import SwiftUI

struct PickerView: View {

    @State var pickerSelection = 0

    init() {
        UISegmentedControl.appearance().tintColor = UIColor.blue
    }

    var body: some View {
        Picker(selection: $pickerSelection, label: Text("")) {
            Text("Active").tag(0).foregroundColor(Color.white)
            Text("Completed").tag(1)
        }.pickerStyle(SegmentedPickerStyle()).foregroundColor(Color.orange)
    }
}

在SwiftUI中有没有做到这一点的方法,或者我应该使用UIViewControllerRepresentable来使用UISegmentedControl?


2
如果我们想在同一个视图中为另一个分段选择器设置不同的色调颜色,应该怎么做? - jamryu
6个回答

121

本地化(但有限)

SwiftUI目前不支持原生的SegmentedPicker样式(查看答案底部的可行解决方法)。但是可以使用.colorMultiply()修饰符以有限的方式将颜色应用于分段选择器:

enter image description here


使用 UIAppearance 全控制

自beta 3以来,selectedSegmentTintColor可用于更改所选段的颜色。

要更改textColor,您应该为.selected状态和.normal状态(未选中)使用setTitleTextAttributes

例如:

init() {
    UISegmentedControl.appearance().selectedSegmentTintColor = .blue
    UISegmentedControl.appearance().setTitleTextAttributes([.foregroundColor: UIColor.white], for: .selected)
    UISegmentedControl.appearance().setTitleTextAttributes([.foregroundColor: UIColor.blue], for: .normal)
}

分段控制器

正如Mike提到的,您也可以设置背景颜色,例如:

UISegmentedControl.appearance().backgroundColor = .yellow

背景演示

另外,别忘了你也可以设置SwiftUI的颜色!例如:

UISegmentedControl.appearance().selectedSegmentTintColor = UIColor(Color.accentColor)

2
请注意,这些属性没有代码补全功能,但是如果您输入它们,它们将编译通过。 - iSpain17
嘿@mojtaba-hosseini @mike,有什么想法可以让它成为“AccentColor”吗? - StuFF mc
2
只需像这样设置 UIColor(Color.accentColor) @StuFFmc - Mojtaba Hosseini
哦,谢谢@MojtabaHosseini。我实际上正在使用UIColor(named: "AccentColor")!。我不知道有这么方便的转换器 :) - StuFF mc
1
最好限制外观的使用。如果父视图足够具体,则不需要将外观重置为nil。这可能会影响应用程序中的其他组件。 let appearance = UISegmentedControl.appearance(whenContainedInInstancesOf: [MyController.self]) - Vladimír Slavík
显示剩余3条评论

7

最近我遇到了一个类似的问题,我需要为SwiftUI SegmentedControl自定义背景前景颜色,我找到了这篇文章,它对我很有帮助,但我还想分享另一种我现在正在使用的解决方案。

有一个非常不错的包叫做SwiftUI Introspect,允许从SwiftUI中内省底层的UIKit组件...

SwiftUI中内省底层的 UIKit 组件

通过使用该包,我创建了下面这个 SegmentedControl

enter image description here 代码如下:

VStack {
    Picker("Activity view", selection: $selectedActivity) {
        ForEach(ActivityView.allCases) { activity in
            Text(activity.description)
        }
    }
    .introspectSegmentedControl { segmentedControl in
        segmentedControl.backgroundColor = .clear
        segmentedControl.tintColor = TCHColors.SegmentedControl.backgroundSelected
        segmentedControl.selectedSegmentTintColor = TCHColors.SegmentedControl.backgroundSelected
        segmentedControl.setTitleTextAttributes([
            NSAttributedString.Key.foregroundColor: TCHColors.SegmentedControl.selectedText
        ], for: .selected)
        segmentedControl.setTitleTextAttributes([
            NSAttributedString.Key.foregroundColor: TCHColors.SegmentedControl.normalText
        ], for: .normal)
    }
    .pickerStyle(.segmented)
}
.padding(.horizontal, 16)

您可以使用此软件包来访问 SwiftUI 中的许多其他基础组件。


我遇到了一个错误:“无法在范围内找到'TCHColors'”,如果您能,请更新代码,谢谢。或者请添加注释以解决它。@Sangsom - Vegas97
1
嗨,这些是从全局应用程序特定枚举文件中使用的颜色,您只需使用UIColor实例更改为所需的颜色,例如UIColor.green。 - Sangsom

2

这里是分段选择器功能的手动实现:

@ViewBuilder func viewSegmentedButtons(arr: [String], selIndex: Int, baseColor: Color, closure:@escaping (_ selectedIndex: Int) -> Void) -> some View {
    
    let columns = Array(repeating: GridItem(spacing: 1), count:arr.count)
    LazyVGrid(columns: columns, spacing: 1.0) {
        ForEach(Array(arr.enumerated()), id: \.element) { index, translation in
            Button {
                closure(index)
            } label: {
                ZStack {
                    Rectangle()
                        .foregroundColor(index == selIndex ? baseColor : Color(.systemBackground))
                        .cornerRadius(radius: index==0 ? cRadius : 0, corners: [.topLeft, .bottomLeft])
                        .cornerRadius(radius: index==arr.count-1 ? cRadius : 0, corners: [.topRight, .bottomRight])
                    Text(translation)
                        .padding(.vertical, 10)
                        .font(.footnote)
                        .foregroundColor(index != selIndex ? baseColor : Color(.systemBackground) )
                }
            }
        }
    }
    .foregroundColor(baseColor)
    .overlay(
        RoundedRectangle(cornerRadius: cRadius)
            .stroke(baseColor, lineWidth: 2)
    )
    .font(.callout)
    .background(baseColor)
    .cornerRadius(cRadius)
    .padding(.bottom, 10)
}

使用示例:

@State private var levelIndex: Int = 0
var body: some View {
    VStack {
        Text("Level:")
        
        viewSegmentedButtons(arr: ["Easy", "Meduim", "Hard"], selIndex: levelIndex, baseColor: .orange) { selectedIndex in
            withAnimation {
                levelIndex = selectedIndex
            }
        }
    }
}

结果: 在此输入图片描述


1

很遗憾,目前没有 SwiftUI 原生的方法来更改分段控件的默认颜色。让我们覆盖默认颜色的解决方案是更改 UISegmentedControl 的外观,就像在 UIKit 应用程序中所做的那样。

为了实现这一点,需要显式定义我们正在处理的视图的 init() 方法:

struct ContentView: View {

init() {
        
    }

 ...
}

init()体内,我们将指定所选段的色调颜色、正常状态下的文本颜色和所选状态下的文本颜色。以下是所有这些操作的实现方式:

init() {
    UISegmentedControl.appearance().selectedSegmentTintColor = .systemIndigo
    UISegmentedControl.appearance().setTitleTextAttributes([.foregroundColor: UIColor.systemYellow], for: .normal)
    UISegmentedControl.appearance().setTitleTextAttributes([.foregroundColor: UIColor.white], for: .selected)
}

以上代码的结果如下所示:

enter image description here

完成

5
你不应该提到整个答案都来自于这篇博客文章吗? - Gabb
哦哦哦,这个回复得到了一个赞。 - James Wolfe
☹️ why @JamesWolfe - Fatemeh

1

这个回答帮了我,但是我有一些东西想要补充。我使用的颜色是作为视图的一个参数,所以将这些方法放在 init 方法中无法访问到颜色。

另外,你可以直接在分段选择器上使用 onAppear 方法,像这样。

import SwiftUI

struct PickerView: View {
    var color: UIColor   
    @State var pickerSelection = 0

    var body: some View {
        Picker(selection: $pickerSelection, label: Text("")) {
            Text("Active").tag(0).foregroundColor(Color.white)
            Text("Completed").tag(1)
        }.pickerStyle(SegmentedPickerStyle()).foregroundColor(Color.orange)
        .onAppear {
            UISegmentedControl.appearance().tintColor = color
        }
    }
}

-2

这是我在SwiftUI中的解决方案:

init(){

    UISegmentedControl.appearance().selectedSegmentTintColor = .green
    UISegmentedControl.appearance().setTitleTextAttributes([.foregroundColor: UIColor.black], for: .selected)

    }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接