51

在遵循 Apple关于用户输入的教程后,我实现了一个切换。目前,它看起来像这样:

这是生成此 UI 的代码:

NavigationView {
    List {
        Toggle(isOn: $showFavoritesOnly) {
            Text("Show Favorites only")
        }
    }
}

现在,我希望Toggle's on -color 是蓝色而不是绿色。
我试过:

Toggle(isOn: $showFavoritesOnly) {
    Text("Show Favorites only")
}
.accentColor(.blue)
.foregroundColor(.blue)
.background(Color.blue)

这些都不起作用,我找不到任何其他修饰符,例如tintColor.

如何更改 a 的颜色Toggle

4

12 回答 12

109

SwiftUI 3.0

使用色调

引入了一个新的修改器,它也可以更改切换颜色:

Toggle(isOn: $isToggleOn) {
    Text("Red")
    Image(systemName: "paintpalette")
}
.tint(.red)

Toggle(isOn: $isToggleOn) {
    Text("Orange")
    Image(systemName: "paintpalette")
}
.tint(.orange)

切换色调颜色

SwiftUI 2.0

使用 SwitchToggleStyle

您现在只能在 SwiftUI 2.0 中为 on 位置设置色调颜色:

Toggle(isOn: $isToggleOn) {
    Text("Red")
    Image(systemName: "paintpalette")
}
.toggleStyle(SwitchToggleStyle(tint: Color.red))

Toggle(isOn: $isToggleOn) {
    Text("Orange")
    Image(systemName: "paintpalette")
}
.toggleStyle(SwitchToggleStyle(tint: Color.orange))

切换色调颜色

SwiftUI 1.0

使用切换样式

我创建了一个新的 ToggleStyle 来更改 Toggle 的三种颜色(打开颜色、关闭颜色和拇指)。

struct ColoredToggleStyle: ToggleStyle {
    var label = ""
    var onColor = Color(UIColor.green)
    var offColor = Color(UIColor.systemGray5)
    var thumbColor = Color.white
    
    func makeBody(configuration: Self.Configuration) -> some View {
        HStack {
            Text(label)
            Spacer()
            Button(action: { configuration.isOn.toggle() } )
            {
                RoundedRectangle(cornerRadius: 16, style: .circular)
                    .fill(configuration.isOn ? onColor : offColor)
                    .frame(width: 50, height: 29)
                    .overlay(
                        Circle()
                            .fill(thumbColor)
                            .shadow(radius: 1, x: 0, y: 1)
                            .padding(1.5)
                            .offset(x: configuration.isOn ? 10 : -10))
                    .animation(Animation.easeInOut(duration: 0.1))
            }
        }
        .font(.title)
        .padding(.horizontal)
    }
}

使用示例

Toggle("", isOn: $toggleState)
    .toggleStyle(
        ColoredToggleStyle(label: "My Colored Toggle",
                           onColor: .green,
                           offColor: .red,
                           thumbColor: Color(UIColor.systemTeal)))

Toggle("", isOn: $toggleState2)
    .toggleStyle(
        ColoredToggleStyle(label: "My Colored Toggle",
                           onColor: .purple))

来自 SwiftUI 书籍

切换示例

于 2019-09-14T02:06:56.513 回答
16

只需使用UIAppearanceAPI:

UISwitch.appearance().onTintColor = UIColor.blue

UISwitch根据UIAppearance文档,它当然会默认更改 的所有实例的外观。

注意:从 Xcode 11 beta 5 开始测试。

于 2019-08-19T18:36:31.350 回答
10

SwiftUI 2.0(WWDC-2020 后)

使用新的 SwiftUI 增强功能,您可以使用.toggleStyle修饰符。

// Switch tinting

Toggle(isOn: $order.notifyWhenReady) {
    Text("Send notification when ready")
}
.toggleStyle(SwitchToggleStyle(tint: .accentColor))

请注意,这仅适用于 iOS14/iPadOS14/macOS11 及更高版本。

于 2020-06-23T18:22:33.903 回答
7

您可以在 init() 中修改所有 UISwitch 对象的全局 onTintColor。

@State var enable_dhcp = true

init()
{
    UISwitch.appearance().onTintColor = .red
}

var body: some View
{
    Toggle("DHCP", isOn: $enable_dhcp)
}

切换演示 UIColor(红色:226.3/255.0,绿色:37.6/255.0,蓝色:40.7/255.0,alpha:1.0)

于 2019-11-08T14:50:06.407 回答
6

我还没有找到直接更改Toggle颜色的方法,但是另一种使用蓝色开关或任何其他自定义视图的方法是创建自己的自定义视图。以最简单的形式制作自定义蓝色切换:

struct BlueToggle : UIViewRepresentable {
  func makeUIView(context: Context) -> UISwitch {
    UISwitch()
  }

  func updateUIView(_ uiView: UISwitch, context: Context) {
    uiView.onTintColor = UIColor.blue
  }
}

struct ContentView : View {
    var body: some View {
      BlueToggle()
    }
}

结果:

在此处输入图像描述

于 2019-06-06T15:25:42.023 回答
6

在 @mohammad-reza-farahani 的解决方案的基础上,这是一种完全不妥协的方法,可以通过 SwiftUI 的实现协议获得 UISwitch 的可配置性。

首先将 a 包裹UISwitch在 a 中UIViewRepresentable并根据需要设置颜色:

final class CustomToggleWrapper: UIViewRepresentable {
    var isOn: Binding<Bool>

    init(isOn: Binding<Bool>) {
        self.isOn = isOn
    }

    func makeUIView(context: Context) -> UISwitch {
        UISwitch()
    }

    func updateUIView(_ uiView: UISwitch, context: Context) {
        // On color
        uiView.onTintColor = UIColor.blue
        // Off color
        uiView.tintColor = UIColor.red
        uiView.layer.cornerRadius = uiView.frame.height / 2
        uiView.backgroundColor = UIColor.red
        uiView.isOn = isOn.wrappedValue

        // Update bound boolean
        uiView.addTarget(self, action: #selector(switchIsChanged(_:)), for: .valueChanged)
    }

    @objc
    func switchIsChanged(_ sender: UISwitch) {
        isOn.wrappedValue = sender.isOn
    }
}

其次,使用 Wrapped创建自定义切换样式UISwitch

struct CustomToggleStyle: ToggleStyle {
    func makeBody(configuration: Self.Configuration) -> some View {
        let toggle = CustomToggleWrapper(isOn: configuration.$isOn)

        return HStack {
            configuration.label
            Spacer()
            toggle
        }
    }
}

像往常一样实施 a Toggle,并应用您的CustomToggleStyle

struct TestView: View {
    @State private var isOn: Bool = true

    var body: some View {
        Toggle(
            isOn: $isOn
        ) {
            Text("Test: \(String(isOn))")
        }.toggleStyle(CustomToggleStyle()).padding()
    }
}
于 2019-12-29T03:17:23.867 回答
4

Karol Kulesza 和 George Valkov 提供了一个非常易于实施的解决方案。我只是想补充一点,您也可以将下面的代码放在应用程序委托的 didFinishLaunching 方法中。

UISwitch.appearance().onTintColor = .blue

您还可以创建更具体的外观配置

appearance(whenContainedInInstancesOf:)

https://www.hackingwithswift.com/example-code/uikit/what-is-the-uiappearance-proxy

于 2020-03-15T09:20:17.800 回答
1

由于最初的问题只是关于改变颜色的切换而不是完全的Toggle视觉定制,我认为这样的事情会做:

import SwiftUI

struct CustomToggle: UIViewRepresentable {
  @Binding var isOn: Bool

  func makeCoordinator() -> CustomToggle.Coordinator {
    Coordinator(isOn: $isOn)
  }

  func makeUIView(context: Context) -> UISwitch {
    let view = UISwitch()
    view.onTintColor = UIColor.red
    view.addTarget(context.coordinator, action: #selector(Coordinator.switchIsChanged(_:)), for: .valueChanged)

    return view
  }

  func updateUIView(_ uiView: UISwitch, context: Context) {
    uiView.isOn = isOn
  }

  class Coordinator: NSObject {
    @Binding private var isOn: Bool

    init(isOn: Binding<Bool>) {
      _isOn = isOn
    }

    @objc func switchIsChanged(_ sender: UISwitch) {
      _isOn.wrappedValue = sender.isOn
    }
  }
}

// MARK: - Previews

struct CustomToggle_Previews: PreviewProvider {
  static var previews: some View {
    ViewWrapper()
  }

  struct ViewWrapper: View {
    @State(initialValue: false) var isOn: Bool

    var body: some View {
      CustomToggle(isOn: $isOn)
        .previewLayout(.fixed(width: 100, height: 100))
    }
  }
}
于 2020-02-05T12:33:43.240 回答
1

我会稍微改变@Mark Moeykens 的回答以避免按钮点击动画。更好的解决方案是:

@available(iOS 13.0, *)
struct ColoredToggleStyle: ToggleStyle {
    var label = ""
    var onColor = UIColor.proacPrimaryBlue.suColor
    var offColor = UIColor.systemGray5.suColor
    var thumbColor = Color.white

    func makeBody(configuration: Self.Configuration) -> some View {
        HStack {
            Text(label)
            Spacer()
            RoundedRectangle(cornerRadius: 16, style: .circular)
                .fill(configuration.isOn ? onColor : offColor)
                .frame(width: 50, height: 29)
                .overlay(
                    Circle()
                        .fill(thumbColor)
                        .shadow(radius: 1, x: 0, y: 1)
                        .padding(1.5)
                        .offset(x: configuration.isOn ? 10 : -10))
                .animation(Animation.easeInOut(duration: 0.1))
                .onTapGesture {
                    configuration.isOn.toggle()
                }
        }
        .font(.title)
        .padding(.horizontal)
    }
}
于 2021-08-04T10:13:09.937 回答
1
  1. 最简单的方法是UISwitch.appearance().onTintColor = UIColor.red在使用切换之前设置并使用 SwiftUI Toggle,如下所示。
UISwitch.appearance().onTintColor = UIColor.red
...

let toggle = Toggle(isOn: $vm.dataUsePermission, label: {
    Text(I18N.permit_data_usage)
        .font(SwiftUI.Font.system(size: 16, weight: .regular))
})

if #available(iOS 14.0, *) {
    toggle.toggleStyle(
        SwitchToggleStyle(tint: Color(UIColor.m.blue500))
    )
} else {
    toggle.toggleStyle(SwitchToggleStyle())
}

...
  1. 您也可以在 SwiftUI 中使用相同的 Toggle 界面但名称不同,并更改色调颜色。

在此处输入图像描述


TintableSwitch(isOn: .constant(true), label: {
    Text("Switch")
})

Toggle(isOn: .constant(true), label: {
    Text("Switch")
})

如果只需要不带标签的切换,那么

TintableUISwitch(isOn: .constant(true))

使用下面的代码。

import SwiftUI

public struct TintableSwitch<Label>: View where Label: View {

    @Binding var isOn: Bool

    var label: Label

    public init(isOn: Binding<Bool>, @ViewBuilder label: () -> Label) {
        self._isOn = isOn
        self.label = label()
    }

    public var body: some View {
        HStack {
            label
            Spacer()
            TintableUISwitch(isOn: $isOn, onTintColor: .red) //  CHANGE HERE
        }
    }
}

public struct TintableUISwitch: UIViewRepresentable {

    @Binding var isOn: Bool
    private var onTintColor: UIColor

    public init(isOn: Binding<Bool>, onTintColor: UIColor = UIColor.m.blue500) {
        self._isOn = isOn
        self.onTintColor = onTintColor
    }

    public func makeUIView(context: Context) -> UISwitch {
        let uiSwitch = UISwitch()
        uiSwitch.addTarget(
            context.coordinator,
            action: #selector(Coordinator.valueChanged(_:)),
            for: .valueChanged
        )
        uiSwitch.onTintColor = onTintColor
        uiSwitch.isOn = isOn
        return uiSwitch
    }

    public func updateUIView(_ uiView: UISwitch, context: Context) {
        uiView.isOn = isOn
    }

    public func makeCoordinator() -> Coordinator {
        Coordinator(self)
    }

    public class Coordinator: NSObject {

        var tintableSwitch: TintableUISwitch

        init(_ tintableSwitch: TintableUISwitch) {
            self.tintableSwitch = tintableSwitch
        }

        @objc
        func valueChanged(_ sender: UISwitch) {
            tintableSwitch.isOn = sender.isOn
        }
    }
}

struct TintableSwitch_Previews: PreviewProvider {
    static var previews: some View {
        VStack {
            TintableSwitch(isOn: .constant(true), label: {
                Text("Switch")
            })

            Toggle(isOn: .constant(true), label: {
                Text("Switch")
            })
        }
    }
}

struct TintableUISwitch_Previews: PreviewProvider {
    static var previews: some View {
        TintableUISwitch(isOn: .constant(true))
    }
}

于 2021-08-25T09:17:02.517 回答
0

这个https://stackoverflow.com/a/56480720/5941807(现在是 Xcode 11 beta 6)是一个解决方案。要在选项之间切换,一种快速的方法是使用布尔值而不是 if/else:

showFavoritesOnly ? .red : .blue

前景:

Toggle(isOn: $showGreeting) {
  Text("Show Favorites only").foregroundColor(showFavoritesOnly ? .blue : .gray)
}

色调:

uiView.onTintColor = showFavoritesOnly ? UIColor.blue : UIColor.gray

除了自定义颜色:https ://stackoverflow.com/a/57744208/5941807

于 2019-09-01T09:08:59.590 回答
0

您可以使用色调修改器更改IOS 15.0中的切换颜色。

Toggle(isOn: $isToggleOn) {
       Text("Toggle")
    }.tint(.red)

在 IOS 15.0 以下,您可以使用 toggleStyle 修饰符来更改切换颜色,但将来会贬值。

 Toggle(isOn: $isToggleOn) {
    Text("Toggle")
 }.toggleStyle(SwitchToggleStyle(tint: .red))
于 2021-11-22T06:56:27.660 回答