SwiftUI:如何从Slider获取连续更新

dre*_*kka 6 ios swift swiftui

我正在尝试像这样的SwiftUI和Slider控件:

struct MyView: View {

    @State private var value = 0.5

    var body: some View {
        Slider(value: $value) { pressed in
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

我试图Slider在用户拖动它时从中获取连续更新,但是似乎它仅在值更改结束时更新值。

有人玩过这个吗?知道如何让SwiftUI滑块发布价值变化流?结合起来?

Pau*_*l B 13

我们可以无需自定义绑定、自定义inits、ObservableObjects、PassthroughSubjects@Published和其他复杂功能。滑块具有.onChange(of: perform:)非常适合这种情况的修饰符。

这个答案可以重写如下:

struct AspectSlider2: View {

    @Binding var value: Int
    let hintKey: String
    @State private var sliderValue: Double = 0.0

    var body: some View {
        VStack(alignment: .trailing) {

            Text(LocalizedStringKey("\(hintKey)\(value)"))

            HStack {
                Slider(value: $sliderValue, in: 0...5)
                    .onChange(of: sliderValue, perform: sliderChanged)
            }
        }
    }

    private func sliderChanged(to newValue: Double) {
        sliderValue = newValue.rounded()
        let roundedValue = Int(sliderValue)
        if roundedValue == value {
            return
        }

        print("Updating value")
        value = roundedValue
    }
}
Run Code Online (Sandbox Code Playgroud)


Mo *_*ani 6

在SwiftUI中,您可以将UI元素(例如滑块)绑定到数据模型中的属性,并在那里实现业务逻辑。

例如,要获得连续的滑块更新:

import SwiftUI
import Combine

final class SliderData: BindableObject {

  let didChange = PassthroughSubject<SliderData,Never>()

  var sliderValue: Float = 0 {
    willSet {
      print(newValue)
      didChange.send(self)
    }
  }
}

struct ContentView : View {

  @EnvironmentObject var sliderData: SliderData

  var body: some View {
    Slider(value: $sliderData.sliderValue)
  }
}
Run Code Online (Sandbox Code Playgroud)

请注意,要使场景使用数据模型对象,您需要将其更新window.rootViewController为SceneDelegate类中的以下内容,否则应用程序将崩溃。

window.rootViewController = UIHostingController(rootView: ContentView().environmentObject(SliderData()))
Run Code Online (Sandbox Code Playgroud)

在此处输入图片说明

  • 要使其在最新的 Xcode 中工作:BindableObject -&gt; ObservableObject - Xcode 11.3 (3认同)

dre*_*kka 5

经过多次玩耍,我最终得到了以下代码。为了保持简短的答案,稍微减少了一点,但在这里。我需要一些东西:

  • 在设置外部绑定之前从滑块读取值更改并将它们四舍五入到最接近的整数。
  • 根据整数设置本地化提示值。
struct AspectSlider: View {

    // The first part of the hint text localization key.
    private let hintKey: String

    // An external integer binding to be set when the rounded value of the slider
changes to a different integer.
    private let value: Binding<Int>

    // A local binding that is used to track the value of the slider.
    @State var sliderValue: Double = 0.0

    init(value: Binding<Int>, hintKey: String) {
        self.value = value
        self.hintKey = hintKey
    }

    var body: some View {
        VStack(alignment: .trailing) {

            // The localized text hint built from the hint key and the rounded slider value.
            Text(LocalizedStringKey("\(hintKey).\(self.value.value)"))

            HStack {
                Text(LocalizedStringKey(self.hintKey))
                Slider(value: Binding<Double>(
                    getValue: { self.$sliderValue.value },
                    setValue: { self.sliderChanged(toValue: $0) }
                    ),
                    through: 4.0) { if !$0 { self.slideEnded() } }
            }
        }
    }

    private func slideEnded() {
        print("Moving slider to nearest whole value")
        self.sliderValue = self.sliderValue.rounded()
    }

    private func sliderChanged(toValue value: Double) {
        $sliderValue.value = value
        let roundedValue = Int(value.rounded())
        if roundedValue == self.value.value {
            return
        }

        print("Updating value")
        self.value.value = roundedValue
    }
}
Run Code Online (Sandbox Code Playgroud)