SwiftUI | Sliderを曲の再生位置に同期させる方法

音声・動画

SwiftUIでSliderを曲の再生位置に同期させる方法を説明する。

Swift 5.7 / Xcode 14.0 / iOS 16.0

結論

ユーザーがSliderを操作したときに曲の再生位置を変更するには、SliderのonEditingChanged内に曲の再生位置を制御する処理を記述する。

曲が進むのに合わせてSliderの位置を追従させるには、Sliderの.onReceive内に曲の再生位置を定期的に取得する処理を記述する。

具体例

以下のAppを作成する。

  1. Sliderと曲の再生位置が同期するようにする。
  2. ユーザーがSliderを操作したときに曲の再生位置を変更するために、SliderのonEditingChanged内に曲の再生位置を制御する処理を記述する。
  3. 曲が進むのに合わせてSliderの位置を追従させるために、Sliderの.onReceive内に曲の再生位置を定期的に取得する処理を記述する。
  4. 1でSliderと曲の再生位置を同期できるように、曲の再生位置を示す変数には@Publishedを付ける。
  5. 3で曲の再生位置を定期的に取得できるように、Timerを記述する。
  6. 再生をタップしたときにViewが更新されないとなぜかTimerが効かないようなので、再生をタップしたときにTextの表示内容が変わるようにする。
import SwiftUI
import AVFoundation


struct ContentView: View {
    @ObservedObject var オーディオインスタンス = オーディオクラス()
    @State private var 再生or停止: String = "▶ 再生"
    var body: some View {
        Button(action: {
            if 再生or停止 == "▶ 再生" {
                再生or停止 = "■ 停止"
                オーディオインスタンス.再生()
                オーディオインスタンス.タイマー開始()
            } else {
                再生or停止 = "▶ 再生"
                オーディオインスタンス.停止()
            }
        }) {
            Text(String(再生or停止))                                  // ? 6
        }
        Slider(value: $オーディオインスタンス.再生位置,                   // ? 1
               in: TimeInterval(0.0)...オーディオインスタンス.曲の長さ,
               onEditingChanged: { _ in
            オーディオインスタンス.再生位置を変更()                        // ? 2
        })
        .onReceive(オーディオインスタンス.timer) { _ in                  // ? 3
            if オーディオインスタンス.isPlaying {
                オーディオインスタンス.再生位置 = オーディオインスタンス.audioPlayer!.currentTime
            } else {
                オーディオインスタンス.タイマー停止()
            }
        }
        .padding()
    }
}

class オーディオクラス: ObservableObject {
    var isPlaying = false
    var audioPlayer: AVAudioPlayer?
    var 曲の長さ: TimeInterval
    @Published var 再生位置: TimeInterval = 0.0                        // ? 4
    var timer = Timer.publish(every: 1, on: .main, in: .common).autoconnect()
    
    init() {
        let path = Bundle.main.path(forResource: "sample", ofType: "mp3")!
        audioPlayer = try! AVAudioPlayer(contentsOf: URL(fileURLWithPath: path))
        曲の長さ = audioPlayer!.duration
    }

    func 再生() {
        audioPlayer?.play()
        isPlaying = true
    }
    
    func 停止() {
        audioPlayer?.pause()
        isPlaying = false
    }
    
    func 再生位置を変更() {
        audioPlayer?.currentTime = 再生位置
    }
    
    func タイマー開始() {
        timer = Timer.publish(every: 1, on: .main, in: .common).autoconnect()  // ? 5
    }
    
    func タイマー停止() {
        timer.upstream.connect().cancel()
    }
}

まとめ

SwiftUIでSliderを曲の再生位置に同期させる方法を説明した。

コメント

タイトルとURLをコピーしました