web-dev-qa-db-fra.com

UISlider pour contrôler AVAudioPlayer

J'essaie d'implémenter une petite fonction dans mon application. Je joue actuellement des sons en tant que AVAudioPlayers et cela fonctionne très bien. Ce que je voudrais ajouter, c'est contrôler la position du son (currentTime) avec un UISlider: existe-t-il un moyen simple de le faire?

J'ai regardé un projet Apple mais c'était assez compliqué .... avez-vous des échantillons ou des suggestions?

Merci à tous d'avance

33
David Pollak

Pour étendre la réponse de paull, vous devez définir le curseur pour qu'il soit continu avec une valeur maximale de duration de votre lecteur audio, puis ajouter un de vos objets (probablement le contrôleur de vue) comme cible pour l'événement UIControlEventValueChanged du curseur; lorsque vous recevez le message d'action, vous devez ensuite définir la propriété AVAudioPlayer de currentTime sur la valeur du curseur. Vous pouvez également utiliser un NSTimer pour mettre à jour la valeur du curseur pendant la lecture du lecteur audio; +scheduledTimerWithTimeInterval:target:selector:userInfo:repeats: est le moyen le plus simple de le faire.

16
Noah Witherspoon

Cela ne devrait pas être un problème - réglez simplement le curseur sur continu et définissez la valeur maximale sur la durée de votre lecteur après le chargement de votre fichier audio.

Modifier

Je viens de faire ça et ça marche pour moi ...

- (IBAction)slide {
    player.currentTime = slider.value;
}

- (void)updateTime:(NSTimer *)timer {
    slider.value = player.currentTime;
}

- (IBAction)play:(id)sender {
    NSURL *url = [NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:@"sound.caf" ofType:nil]];
    NSError *error;
    player = [[AVAudioPlayer alloc] initWithContentsOfURL:url error:&error];
    if (!player) NSLog(@"Error: %@", error);
    [player prepareToPlay];
    slider.maximumValue = [player duration];
    slider.value = 0.0;

    [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(updateTime:) userInfo:nil repeats:YES];  
    [player play];
}

Le curseur est configuré dans IB, tout comme un bouton pour commencer à jouer.

Mise à jour Swift 3.0:

var player: AVAudioPlayer!
var sliderr: UISlider!

@IBAction func play(_ sender: Any) {
    var url = URL(fileURLWithPath: Bundle.main.path(forResource: "sound.caf", ofType: nil)!)
    var error: Error?
    do {
        player = try AVAudioPlayer(contentsOf: url)
    }
    catch let error {
    }
    if player == nil {
        print("Error: \(error)")
    }
    player.prepareToPlay()
    sliderr.maximumValue = Float(player.duration)
    sliderr.value = 0.0
    Timer.scheduledTimer(timeInterval: 1.0, target: self, selector: #selector(self.updateTime), userInfo: nil, repeats: true)
    player.play()
}

func updateTime(_ timer: Timer) {
    sliderr.value = Float(player.currentTime)
}

@IBAction func slide(_ slider: UISlider) {
    player.currentTime = TimeInterval(slider.value)
}
51
Paul Lynch

J'avais besoin d'adapter un peu la réponse ci-dessus pour qu'elle fonctionne. Le problème est que l'utilisation

slider.maximumValue = [player duration];
slider.value = player.currentTime;
player.currentTime = slider.value;

Ne fonctionne pas car le curseur attend un flottant et le lecteur currentTime et dration renvoient CMTime. Pour les faire fonctionner, je les ai adaptés pour lire:

slider.maximumValue = CMTimeGetSeconds([player duration]);
slider.value = CMTimeGetSeconds(player.currentTime);
player.currentTime = CMTimeMakeWithSeconds((int)slider.value,1);
7
3leggedcheetah

Problèmes rencontrés lors de la lecture d'un fichier audio et de l'heure de début/fin et du contrôle de la chanson avec UISlider.

  1. Ne pas lire l'audio directement sans le télécharger dans le dossier temporaire.
  2. UISlider s'est écrasé sur le thread principal dans la version iOS inférieure, à savoir 12.4/13.1
  3. Défilement fluide d'UISlider.
  4. Calcul et mise à jour de l'heure de début/fin de la chanson.

Cette réponse nécessite quelques modifications, mais elle fonctionnera sans aucun doute.

  //UISlider init
  lazy var slider: UISlider = {
    let progress = UISlider()
    progress.minimumValue = 0.0
    progress.maximumValue = 100.0
    progress.tintColor = UIColor.init(named: "ApplicationColor")
    return progress

}()

 var audioPlayer : AVAudioPlayer?
   //First I've downloaded the audio and then playing it.
  override func viewWillAppear(_ animated: Bool) {

    super.viewWillAppear(animated)


    timer = Timer.scheduledTimer(timeInterval: 1, target: self, selector: #selector(trackAudio), userInfo: nil, repeats: true)

    if let audioURLString = audioURL{
        let urlstring = URL(string: audioURLString)!
        downloadFromURL(url: urlstring) { (localURL, response, error) in
            if let localURL = localURL{
                self.playAudioFile(url: localURL)
            }

        }
    }
}

 override func viewDidDisappear(_ animated: Bool) {
    super.viewDidDisappear(animated)
    stopTimer()
}


// Stop TimeInterval After View disappear
func stopTimer() {
    if timer != nil {
        timer?.invalidate()
        audioPlayer?.stop()
        audioPlayer = nil
        timer = nil
    }
}
@objc func sliderSelected(_ sender : UISlider){

    if audioPlayer != nil{
        if !isPlaying{
            self.audioPlayer?.play()
            playButton.setImage(UIImage.init(named: "AudioPause"), for: .normal)
            isPlaying = true
        }else{
            self.audioPlayer?.currentTime = TimeInterval(Float(sender.value) * Float(self.audioPlayer!.duration) / 100.0)
            if (sender.value / 100.0 == 1.0){

                //Do something if audio ends while dragging the UISlider.

            }
        }


    }

}
 func downloadFromURL(url:URL,completion: @escaping((_ downladedURL: URL?,_ response :URLResponse?,_ error: Error?) -> Void)){
    var downloadTask:URLSessionDownloadTask
    downloadTask = URLSession.shared.downloadTask(with: url) {(URL, response, error) in
        if let url = URL{
            completion(url,nil,nil)
        }else if let response = response{
            completion(nil,response,nil)
        }
        if let error = error{
            completion(nil,nil,error)
        }


    }

    downloadTask.resume()
}


func playAudioFile(url:URL){
    do{

        self.audioPlayer = try AVAudioPlayer(contentsOf: url)
        self.audioPlayer?.prepareToPlay()
        self.audioPlayer?.delegate = self
        self.audioPlayer?.play()

   let audioDuration = audioPlayer?.duration
        let audioDurationSeconds = audioDuration
        minutes = Int(audioDurationSeconds!/60);
        seconds =  Int(audioDurationSeconds!.truncatingRemainder(dividingBy: 60))
    } catch{
        print("AVAudioPlayer init failed")
    }
}

@objc func trackAudio() {

    if audioPlayer != nil{
        DispatchQueue.main.async {
            print("HI")
            let normalizedTime = Float(self.audioPlayer!.currentTime * 100.0 / self.audioPlayer!.duration)
            self.slider.setValue(normalizedTime, animated: true)
            let currentTime = self.audioPlayer?.currentTime
            self.currentMinutes = Int(currentTime!/60);
            self.currentSeconds =  Int(currentTime!.truncatingRemainder(dividingBy: 60))
            self.startTimeLabel.text =  String(format: "%02i:%02i", self.currentMinutes, self.currentSeconds)
            self.endTimeLabel.text = String(format: "%02i:%02i", self.minutes, self.seconds)
        }
    }





}
0
Shanu Singh