SwiftUI Combine-音频高位可视化器

时间:2020-04-07 20:22:42

标签: swiftui combine

我正在尝试使用Combine来复制旧的立体声可视化器在SwiftUI中的工作方式。 我可以发布当前数据量的随机数据,然后希望该数据量减少到零,除非传入新的高点。

  • 尝试1几乎可以工作,除了值开始减小之前没有延迟。
  • 尝试2,通过设置音量后延迟,感觉应该可以工作,但是然后我又遇到了将变量设置回原来的问题

除了专门使用Combine Publishers之外,谁能给我任何有关如何创建此效果的指示?

import SwiftUI
import Combine

/**
 Think of an old audio equalizer/visualizer, as sound is played, it visually goes high, but then fades back down
 to zero, that's what I'm trying to replicate, vut using Swift Combine Publishers

 The highest value will be assigned to $volume

 After a second of being displayed, the $volume should decrease over a short amount of time back to zero
 However, if a new higher $volume is set, then the new highest number is displayed, wait a second and start
 to decrease again
 */
class Throughput: ObservableObject {

    private var cancellables = Set<AnyCancellable>()

    /// Creates random flow volume data over time
    private let dataPublisher = Timer.publish(every: 1.0, on: .main, in: .default)
    private var dataCancelable: AnyCancellable?

    /// Remove 1 until `volume` is back to zero
    private let resetPublisher = Timer.publish(every: 0.1, on: .main, in: .default)
    private var resetCancelable: AnyCancellable?

    @Published private var internalvolume: Int = 0
    @Published private(set) var volume: Int = 0

    init() {

        /**
        Publish values over time
        */
         dataCancelable = dataPublisher
                   .autoconnect()
                   .map({ _ in Int.random(in: 0..<100) })
                   .map({
                       if $0 > self.volume {
                           return $0
                       } else {
                           return nil
                       }
                   })
                   .compactMap({ $0 })
                   .assign(to: \.volume, on: self)

        /**
        When the volume is changed, pause, then quickly decrease the value of volume to zero unless a new high point found
        */

        /**
         Attemp 1 just uses another timer to decrease from the volume, the issue here is there is no delay before it starts
         */
        resetCancelable = resetPublisher
            .autoconnect()
            .map({ _ in
                var current = self.volume
                if current > 0 {
                    current -= 1
                }
                return current
                })
            .assign(to: \.volume, on: self)

        /**
         Attempt 2 - Feels like it would be the better option, delaying the action
         */
//        $volume
//            .delay(for: .seconds(1), tolerance: .none, scheduler: RunLoop.main, options: nil)
//            .map({ _ in
//                var current = self.volume
//                if current > 0 {
//                    current -= 1
//                }
//                self.volume = current
//                })
//            .sink { () in
//
//        }.store(in: &cancellables)

    }
}

extension Int {
    var stringValue: String {
        String(self)
    }
}

struct ContentView: View {

    @ObservedObject var flow: Throughput = Throughput()

    var body: some View {
        Text(flow.volume.stringValue)
    }
}

谢谢

0 个答案:

没有答案