Остановка воспроизведения звука при открытии другой группы раскрытия в приложении диктофонаIOS

Программируем под IOS
Ответить Пред. темаСлед. тема
Anonymous
 Остановка воспроизведения звука при открытии другой группы раскрытия в приложении диктофона

Сообщение Anonymous »

Я работаю над приложением для записи голоса, используя SwiftUI. В настоящее время у меня есть интерфейс проигрывателя в DisclosureGroup, например: https://imgur.com/a/GmLvmMh. Воспроизведение звука прекращается, когда вы закрываете текущую DisclosureGroup, а также одновременно можно открыть только одну DisclosureGroup. Однако я не могу сделать так, чтобы воспроизведение звука прекращалось при открытии другой DisclosureGroup.
Код для моего плеера находится здесь:

Код: Выделить всё

import Foundation
import AVFoundation
import SwiftUI
import Combine

class Player: NSObject, ObservableObject, AVAudioPlayerDelegate {
var player: AVAudioPlayer?
let objectWillChange = PassthroughSubject()

var isPlaying = false {
didSet {
objectWillChange.send()
}
}

@Published var currentTime: TimeInterval = 0
private var timer: AnyCancellable?

init(soundURL: URL) throws {
super.init()
if FileManager().fileExists(atPath: soundURL.path) {
do {
self.player = try AVAudioPlayer(contentsOf: soundURL)
player?.prepareToPlay()
self.player?.delegate = self
} catch {
throw Errors.FailedToPlayURL
}
} else {
print("URL not valid!")
}
}

func play() {
self.player?.play()
isPlaying = true
startTimer()
}

func pause() {
if isPlaying {
self.player?.pause()
isPlaying = false
stopTimer()
}
}

func stop() {
player?.stop()
isPlaying = false
resetPlayback()
}

func seek(to time: TimeInterval) {
player?.currentTime = time
currentTime = time
}

var duration: TimeInterval {
player?.duration ?? 0
}

private func startTimer() {
timer = Timer.publish(every: 0.1, on: .main, in: .common)
.autoconnect()
.sink { [weak self] _ in
guard let self = self else { return }
self.currentTime = self.player?.currentTime ?? 0
self.objectWillChange.send()
}
}

private func stopTimer() {
timer?.cancel()
timer = nil
}

func audioPlayerDidFinishPlaying(_ player: AVAudioPlayer, successfully flag: Bool) {
if flag {
isPlaying = false
stopTimer()
resetPlayback()
}
}

private func resetPlayback() {
currentTime = 0
player?.currentTime = 0
objectWillChange.send()
}
}

Код моей PlayerViewModel находится здесь:

Код: Выделить всё

import Foundation
import Combine

class PlayerViewModel: ObservableObject {
@Published var currentTime: TimeInterval = 0
var player: Player
private var cancellables = Set()
private var seekingSubject = PassthroughSubject()

init(player: Player) {
self.player = player
self.player.objectWillChange
.sink { [weak self] in
self?.currentTime = self?.player.currentTime ?? 0
}
.store(in: &cancellables)

seekingSubject
.throttle(for: .milliseconds(100), scheduler: RunLoop.main, latest: true)
.sink { [weak self] time in
self?.player.seek(to: time)
}
.store(in: &cancellables)
}

func play() {
player.play()
}

func pause() {
player.pause()
}

func stop() {
player.stop()
}

func seek(to time: TimeInterval) {
seekingSubject.send(time)
}

var duration: TimeInterval {
player.duration
}
}

Наконец, код моего PlayerView здесь. В настоящее время я определяю открытие группы раскрытия по URL-адресу, к которому она привязана. Таким образом, когда открывается группа раскрытия, открытие другой закрывает текущую. Я пытался поместить сюда viewModel.stop(), но безрезультатно:

Код: Выделить всё

import SwiftUI
import AVFoundation

struct PlayerView: View {
@State var soundURL: URL
@Binding var openedGroup: URL?
@State private var isOpened: Bool = false

@StateObject private var viewModel: PlayerViewModel
@State private var sliderValue: TimeInterval = 0

init(soundURL: URL, openedGroup: Binding) {
self._soundURL = State(initialValue: soundURL)
self._openedGroup = openedGroup
let player = try? Player(soundURL: soundURL)
self._viewModel = StateObject(wrappedValue: PlayerViewModel(player: player!))
}

var body: some View {
DisclosureGroup(isExpanded: Binding(
get: { self.openedGroup == self.soundURL },
set: { newValue in
if newValue {
self.openedGroup = self.soundURL
} else if self.openedGroup == self.soundURL {
self.openedGroup = nil
viewModel.stop()
}
}
)) {
VStack {
Slider(value: $sliderValue, in: 0...viewModel.duration, onEditingChanged: { editing in
if editing {
viewModel.pause()
} else {
viewModel.seek(to: sliderValue)
viewModel.play()
}
})
.padding()
.onChange(of: viewModel.currentTime) {
sliderValue = viewModel.currentTime
}

HStack {
Text(timeString(from: viewModel.currentTime))
Spacer()
Text(timeString(from: viewModel.duration))
}
.padding(.horizontal)

HStack {
Spacer()
Image(systemName: viewModel.player.isPlaying ? "pause.fill" : "play.fill")
.onTapGesture {
if viewModel.player.isPlaying {
viewModel.pause()
} else {
viewModel.play()
}
}
Spacer()
}
Spacer()
FileNameButtonView(soundURL: soundURL)
}
} label: {
Text(soundURL.lastPathComponent)
}
}

private func timeString(from timeInterval: TimeInterval) -> String {
let minutes = Int(timeInterval) / 60
let seconds = Int(timeInterval) % 60
return String(format: "%02d:%02d", minutes, seconds)
}
}
Если вы хотите просмотреть полный репозиторий, он находится здесь: https://github.com/aabagdi/MemoMan/.
Спасибо за любую помощь!< /п>

Подробнее здесь: https://stackoverflow.com/questions/786 ... ice-record
Реклама
Ответить Пред. темаСлед. тема

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

  • Похожие темы
    Ответы
    Просмотры
    Последнее сообщение

Вернуться в «IOS»