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

时间:2019-06-23 15:01:29

标签: ios swift swiftui

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

Slider

我试图在用户拖动时从{{1}}获取连续更新,但是看来它仅在值更改结束时更新值。

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

6 个答案:

答案 0 :(得分:5)

在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)
  }
}

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

window.rootViewController = UIHostingController(rootView: ContentView().environmentObject(SliderData()))

enter image description here

答案 1 :(得分:2)

在版本11.4.1(11E503a)和Swift 5中。我没有复制它。 通过使用Combine,我可以不断从滑块更改中进行更新。

class SliderData: ObservableObject {

  @Published var sliderValue: Double = 0
  ...

}

struct ContentView: View {

  @ObservedObject var slider = SliderData()

  var body: some View {
    VStack {
      Slider(value: $slider.sliderValue)
      Text(String(slider.sliderValue))
    } 
  }
}  

答案 2 :(得分:1)

我无法在iOS 13 Beta 2上重现此问题。您将目标对准哪个操作系统?

使用自定义绑定,不仅可以在编辑结束之后,还可以为每个小的更改打印值。

Slider(value: Binding<Double>(getValue: {0}, setValue: {print($0)}))

请注意,闭包({ pressed in })仅在编辑结束开始和结束时报告,值流仅传递到绑定中。

答案 3 :(得分:0)

经过大量的尝试,我得到了以下代码。为了使答案简短一点,它做了一些削减,但是这里有。我需要做几件事:

  • 要在设置外部绑定之前从滑块读取值更改并将其四舍五入到最接近的整数。
  • 要基于整数设置本地化的提示值。
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
    }
}

答案 4 :(得分:0)

iOS 13.4,Swift 5.x

一个基于Mohammid极好的解决方案的答案,只是我不想使用环境变量。

class SliderData: ObservableObject {
let didChange = PassthroughSubject<SliderData,Never>()

@Published var sliderValue: Double = 0 {
  didSet {
    print("sliderValue \(sliderValue)")
    didChange.send(self)
   }
  }
}

@ObservedObject var sliderData:SliderData

Slider(value: $sliderData.sliderValue, in: 0...Double(self.textColors.count))

对ContentView_Preview进行很小的更改,在SceneDelegate中进行相同的操作。

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
      ContentView(sliderData: SliderData.init())
    }
}

答案 5 :(得分:0)

只需使用Slider的onEditingChanged参数即可。当用户移动滑块或仍与滑块接触时,该参数为true。当参数从true更改为false时,我会进行更新。

struct MyView: View {

    @State private var value = 0.5

    func update(changing: Bool) -> Void {
        // Do whatever
    }

    var body: some View {
        Slider(value: $value, onEditingChanged: {changing in self.update(changing) }) 
        { pressed in }
    }
}