如何在 SwiftUI 中自定义 Slider 蓝线?

Posted

技术标签:

【中文标题】如何在 SwiftUI 中自定义 Slider 蓝线?【英文标题】:How customise Slider blue line in SwiftUI? 【发布时间】:2019-11-27 19:35:53 【问题描述】:

点赞UISlider

let slider = UISlider()

slider.minimumTrackTintColor = .red

【问题讨论】:

我不明白这个问题的票数接近。这是一个完全合理的问题。 【参考方案1】:

从 Apple 的 2021 平台开始,您可以使用 tint 修饰符来更改滑块旋钮左侧轨道的颜色。除此之外,SwiftUI 的Slider 不允许您自定义其外观。

如果您需要更多自定义,那么目前您唯一的选择是创建一个UISlider 并将其包装在UIViewRepresentable 中。通过the “Interfacing with UIKit” tutorial 和观看WWDC 2019 Session 231: Integrating SwiftUI 学习如何使用UIViewRepresentable

The Slider documentation 之前提到了一个名为SliderStyle 的类型,但是没有关于SliderStyle 的文档,并且该类型实际上并没有在 Xcode 11 beta 4 的 SwiftUI 框架的公共接口中定义。有可能是它将出现在以后的版本中。我们也有可能必须等待 SwiftUI 的未来(13 之后)版本才能获得此功能。

如果确实出现了SliderStyle,它可能允许您自定义Slider 的外观,就像ButtonStyle 允许您自定义Button 的外观一样——通过承担绘制它的全部责任。因此,如果您想抢先一步,您可能想在网上寻找 ButtonStyle 教程。

SliderStyle 最终可能更像TextFieldStyle。 Apple 提供了少量TextFieldStyles 供你选择,但你无法定义自己的。

【讨论】:

.accentColor(.red) 对于 TextFieldStyle,私有 API 是 struct MyTextFieldStyle: TextFieldStyle func _body(configuration: TextField<_Label>) -> some View configuration.foregroundColor(.red) 。来源(谢谢!):swiftwithmajid.com/2020/02/26/textfield-in-swiftui。提醒:这是私有/内部/未记录的 API,将来可能会中断或导致其他问题。【参考方案2】:
.accentColor(.red)

这适用于 ios 和 Mac Catalyst。 查看可自定义的滑块示例here

【讨论】:

项目现在将在以下链接下找到:github.com/spacenation/swiftui-sliders【参考方案3】:

正如在其他答案中指出的那样,您在 SwiftUI 中自定义 Slider 的能力有限。您可以更改.accentColor(.red),但这只会更改minimumTrackTintColor。

Slider.accentColor(.red) 的示例

此外,您无法更改 thumbTintColor 等其他内容。 如果您想要更多的自定义,而不仅仅是minimumTrackTintColor,那么您别无选择,只能在SwiftUI 中使用UISlider,如rob mayoff 所述。

这里是一些关于如何在 SwiftUI 中使用 UISlider 的代码

struct SwiftUISlider: UIViewRepresentable 

  final class Coordinator: NSObject 
    // The class property value is a binding: It’s a reference to the SwiftUISlider
    // value, which receives a reference to a @State variable value in ContentView.
    var value: Binding<Double>

    // Create the binding when you initialize the Coordinator
    init(value: Binding<Double>) 
      self.value = value
    

    // Create a valueChanged(_:) action
    @objc func valueChanged(_ sender: UISlider) 
      self.value.wrappedValue = Double(sender.value)
    
  

  var thumbColor: UIColor = .white
  var minTrackColor: UIColor?
  var maxTrackColor: UIColor?

  @Binding var value: Double

  func makeUIView(context: Context) -> UISlider 
    let slider = UISlider(frame: .zero)
    slider.thumbTintColor = thumbColor
    slider.minimumTrackTintColor = minTrackColor
    slider.maximumTrackTintColor = maxTrackColor
    slider.value = Float(value)

    slider.addTarget(
      context.coordinator,
      action: #selector(Coordinator.valueChanged(_:)),
      for: .valueChanged
    )

    return slider
  

  func updateUIView(_ uiView: UISlider, context: Context) 
    // Coordinating data between UIView and SwiftUI view
    uiView.value = Float(self.value)
  

  func makeCoordinator() -> SwiftUISlider.Coordinator 
    Coordinator(value: $value)
  


#if DEBUG
struct SwiftUISlider_Previews: PreviewProvider 
  static var previews: some View 
    SwiftUISlider(
      thumbColor: .white,
      minTrackColor: .blue,
      maxTrackColor: .green,
      value: .constant(0.5)
    )
  

#endif

然后你可以像这样在ContentView 中使用这个滑块:

struct ContentView: View 
  @State var sliderValue: Double = 0.5

  var body: some View 
    VStack 
      Text("SliderValue: \(sliderValue)")
      // Slider(value: $sliderValue).accentColor(.red).padding(.horizontal)

      SwiftUISlider(
        thumbColor: .green,
        minTrackColor: .red,
        maxTrackColor: .blue,
        value: $sliderValue
      ).padding(.horizontal)
    
  

例子:

Link to full project

【讨论】:

.accentColor(.red) 在我的 macOS 项目(Xcode 12.2 beta 4,macOS 11 RC)中无效。【参考方案4】:

如果亮白色滑块手柄不适合您的暗模式设计,您可以使用 .label color 和 .softLight 来告诉它慢下来。除非你能弄清楚混合模式和色调旋转,否则它只会在灰度下看起来不错。

最好看的结果来自一个覆盖了 .blendMode(.sourceAtop)... 的形状,但遗憾的是,这会阻止交互。


@Environment(\.colorScheme) var colorScheme

var body: some View 

        let hackySliderBGColor: Color = colorScheme == .dark ? Color(.secondarySystemBackground) : Color(.systemBackground)
        let hackySliderAccentColor: Color = colorScheme == .dark ? Color(.label) : Color(.systemGray2)
        let hackySliderBlendMode: BlendMode = colorScheme == .dark ? .softLight : .multiply

...

    ZStack 
            Rectangle()
            .foregroundColor(hackySliderBGColor)

// This second Rect prevents a white sliver if slider is at max value.
             .overlay(Rectangle()
                  .foregroundColor(hackySliderBGColor)
                  .offset(x: 5)
             )

            Slider(value: $pointsToScoreLimit, 
                   in: themin...themax, step: 5)
            .accentColor(hackySliderAccentColor)
            .blendMode(hackySliderBlendMode)
    


示例:

【讨论】:

以上是关于如何在 SwiftUI 中自定义 Slider 蓝线?的主要内容,如果未能解决你的问题,请参考以下文章

SwiftUI:如何在 MapKit 中自定义地理区域的位置?

如何在 SwiftUI 中自定义角度变化的动画

如何在 SwiftUI WidgetKit 占位符中自定义占位符外观?

在 SwiftUI WebView 中自定义内容(添加页脚和页眉注释)

SwiftUI脑洞大开打造实时显示当前值的Slider

SwiftUI脑洞大开打造实时显示当前值的Slider(滑动器)