Я пытаюсь повторить, как работает старый стерео визуализатор в SwiftUI с использованием Combine. Я могу опубликовать sh случайные данные, которые являются моим текущим объемом, и затем я хочу, чтобы объем уменьшился до нуля, если только не будет передана новая высокая точка.
- Попытка 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)
}
}
Спасибо