2017-08-13 3 views
0

Hintergrund: Ich habe ein UITableView, das anfangs ein paar Standard-UITableViewCells lädt. Wenn auf eine davon geklickt wird, wird die Tabelle neu geladen, aber die Zelle, auf die geklickt wurde, wird zu einer benutzerdefinierten Unterklasse namens "RecordingTableCell", die über zwei UILabels, eine UIButton und einen UISlider verfügt. Dies funktioniert im Moment gut.UISlider & UILabels auf benutzerdefinierter Tabellenansicht Zelle wird nicht mit Avaudioplayer aktualisiert, bis Audio ein zweites Mal abgespielt wird

Wenn die Taste gedrückt wird, wird ein AVAudioPlayer eingerichtet und eine Audiodatei abgespielt. Die Methode, die das tut ([self setupAudio]), erhält aber auch die 2 UILabels und UISlider, damit sie mit dem Fortschritt der Audiodaten aktualisiert werden können (ich bin mir nicht sicher, ob ich sie richtig hinbekomme).

Wenn die Wiedergabetaste zum ersten Mal gedrückt wird, wird das Audiomaterial abgespielt, aber der Schieberegler oder die Beschriftungen ändern sich überhaupt nicht. Nachdem die Audiodatei jedoch beendet wurde (d. H. Sobald audioPlayerDidFinishPlaying aufgerufen wird), funktioniert alles, wie es sollte, wenn die Wiedergabetaste erneut gedrückt wird. Hier

The code running in the simulator

ist der Code: (! Sorry für den großen Block)

... 

-(void)setupAudio 
{ 
    //Get path 
    recordingPaths = [[NSUserDefaults standardUserDefaults] objectForKey:@"recordingPaths"]; 
    recordedAudioURL = [NSURL URLWithString:recordingPaths[selectedRowIndex.row]]; 

    NSError *audioError; 
    player = [[AVAudioPlayer alloc] initWithContentsOfURL:[self recordedAudioURL] error:&audioError]; 
    player.delegate = self; 

    [player prepareToPlay]; 

    recordingCurrentCell = (RecordingTableCell *)[self.tableView viewWithTag:REC_TABLE_CELL_TAG]; 

    //The following are subviews of recordingTableCell 
    currentTimeLabel = [recordingCurrentCell currentTimeLabel]; 
    totalTimeLabel = [recordingCurrentCell totalTimeLabel]; 
    slider = [recordingCurrentCell progressSlider]; 

    //Setup slider & labels 
    slider.maximumValue = [player duration]; 
    totalTimeLabel.text = [NSString stringWithFormat:@"%.1f", player.duration]; 

    slider.value = 0.0; 
    currentTimeLabel.text = [NSString stringWithFormat:@"%.1f", slider.value]; 
} 

-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath 
{ 
    [self.tableView deselectRowAtIndexPath:indexPath animated:YES]; 

    selectedRowIndex = indexPath; 
    rowSelected=YES; 

    //Update the table so that the row with an indexPath equal to 'selectedRowIndex' becomes a custom subclass of UITableViewCell 
    [tableView beginUpdates]; 
    [self.tableView reloadData]; 
    [tableView endUpdates]; 

    if(!player) 
    { 
     if(selectedRowIndex.row!=indexPath.row) 
     { 

      [[self player] stop]; 
      player=nil; 

      //Change button on selected cell to the 'play' image 
      [actionButton setImage:[UIImage imageNamed:@"play.png"] forState:UIControlStateNormal]; 

      //If the NSTimer is still going, invalidate it 
      if(timer) 
      { 
       [timer invalidate]; 
       timer = nil; 
      } 
     } 
    } 
    [self setupAudio]; 
} 

//This is hooked up to the button on the custom tableviewcell 
- (IBAction)actionButtonPressed:(id)sender 
{ 
    actionButton = (UIButton *)sender; 

    if(!player.playing) 
    { 
     [actionButton setImage:[UIImage imageNamed:@"pause.png"] forState:UIControlStateNormal]; 

     [timer invalidate]; 
     timer = nil; 

     [player play]; 
     timer = [NSTimer scheduledTimerWithTimeInterval:0.5 target:self selector:@selector(updateTime:) userInfo:nil repeats:YES]; 
     [[NSRunLoop mainRunLoop] addTimer:timer forMode:NSRunLoopCommonModes]; 
    } 
    else 
    { 
     if(timer) 
     { 
      [timer invalidate]; 
      timer = nil; 
     } 
     [actionButton setImage:[UIImage imageNamed:@"play.png"] forState:UIControlStateNormal]; 
     [player pause]; 
    } 
} 

//This is connected to the slider on the custom tableviewcell. 
- (IBAction)slide:(id)sender 
{ 
    if(player) 
    { 
     player.currentTime = slider.value; 
    } 
    currentTimeLabel.text = [NSString stringWithFormat:@"%.1f", slider.value]; 
} 


- (void)updateTime:(NSTimer *)timer 
{ 
    if(player) 
    { 
     slider.value = player.currentTime; 
     currentTimeLabel.text = [NSString stringWithFormat:@"%.1f", slider.value]; 
    } 
} 


- (void)audioPlayerDidFinishPlaying:(AVAudioPlayer *)player successfully:(BOOL)flag 
{ 
    if(timer) 
    { 
     [timer invalidate]; 
     timer = nil; 
    } 

    [self setupAudio]; 
    [actionButton setImage:[UIImage imageNamed:@"play.png"] forState:UIControlStateNormal]; 
} 

Ich habe versucht, um einige der Bits zu bewegen und ich bin nicht sicher, ob ich gehe falsch beim Abrufen der 'RecordingTableCell'-Subviews in [self setupAudio], oder wenn es ein Fehler beim Einrichten des Audio-Players ist.

Jede Hilfe würde sehr geschätzt werden!

Antwort

0

Ich bin mir nicht sicher, ob dies der richtige Weg ist (dh es könnte etwas Grundlegenderes hier fehlen), aber ich habe es geschafft, das Problem zu lösen, indem ich eine boolesche Variable erstellt habe Es ist das erste Mal, dass der AVAudioPlayer für eine Aufnahme eingerichtet wird, und falls dies der Fall ist, instanziieren Sie die Subviews erneut in der actionButtonPressed-Methode.

2

ich denke, die Strom/Dauer des Spielers ein Doppeltyp ist, können Sie die folgenden Methoden verwenden es als String zu erhalten:

func getTimeString(from duration:Double) -> String{ 

     let hours = Int(duration/3600) 
     let minutes = Int(duration/60) % 60 
     let seconds = Int(duration.truncatingRemainder(dividingBy: 60)) 
     if hours > 0 { 
      return String(format: "%:%02i:%02i", arguments: [hours,minutes,seconds]) 
     }else { 
      return String(format: "%02i:%02i", arguments: [minutes,seconds]) 
     } 

    } 

Aktuelle Zeit String:

func getCurrentTimeAsString() -> String{ 

     guard let time = player?.currentTime else { 
      return "00:00" 
     } 

     return getTimeString(from: time) 
    } 

Gesamtspielzeit String:

func getDurationAsString() -> String{ 

     guard let time = player?.duration else { 
      return "00:00" 
     } 
     return getTimeString(from: time) 
    } 

Get Process Wert:

func getProgressValue()->Float{ 
     var theCurrentTime = 0.0 
     var theDuration = 0.0 
     if let currentTime = player?.currentTime,let duration = player?.duration { 
      theCurrentTime = currentTime 
      theDuration = duration 
     } 
     return Float(theCurrentTime/theDuration) 
    } 

Und Sie brauchen einen Timer zu verwenden, um den aktuellen Zeitbeschriftungstext zu aktualisieren, vergessen Sie nicht, den Timer zu stoppen.

timer = Timer.scheduledTimer(withTimeInterval: 0.5, repeats: true, block: {[unowned self] (timer:Timer) in 
       self.updateUIWithTimer() 
      }) 

    func updateUIWithTimer(){ 

     currentTimeLabel.text = getCurrentTimeAsString() 

     timeSlider.value = getProgressValue() 

    }   
+0

Dank für Ihre Antwort danken (+1), habe ich den Code in Swift getestet und es funktioniert auf seine eigene, aber wenn es in meiner ursprünglichen objc Einbeziehung würde ich immer noch, dass es die gleichen Fehler Die UISlider & UILabels antworten erst nach dem zweiten Spiel. –

Verwandte Themen