使用AVAudioPlayer的tableview

时间:2014-08-03 18:48:33

标签: ios uitableview avfoundation avaudioplayer

在我的一个视图控制器中,我有tableview个自定义tableviewcells。每个单元格都与唯一的音频文件相关联。每个单元格也有一个进度条。当我点击单元格播放音频文件并向下滚动时,我注意到重用单元格的进度条也在更新。我创建了一个名为OSTablePlayerController的自定义NSObject类,其中包含AVAudioPlayer及其功能。但是,我在自定义NSTimer课程中设置了tableviewcell。当我点击一个单元格进行播放时,将在我的自定义tableviewcell类中调用以下方法:

-(void) rowSelected2: (NSURL*) url
{
    self.audioPlayer = [OSTablePlayerController getInstance];
    NSData *data=[NSData dataWithContentsOfURL:url];
    [self.audioPlayer playAudio:data];
    self.audioPlayer.isPlayerPlaying = YES;
    self.timer = [NSTimer timerWithTimeInterval:0.01 target:self selector:@selector(updateProgress:) userInfo:nil repeats:YES];
    [[NSRunLoop mainRunLoop] addTimer:self.timer forMode:NSRunLoopCommonModes];  
}  

- (void)updateProgress:(NSTimer *)timer 
{

    NSTimeInterval playTime = [self.audioPlayer currentTime];
    NSTimeInterval duration = [self.audioPlayer duration];

    float progress =  playTime/duration;

    [self.waveView setProgress:progress];

    if(!(self.audioPlayer.player.playing))
    {
        [self audioPlayerDidFinishPlaying:self.audioPlayer.player successfully:YES];

        progress = 0.00;

        [self.waveView setProgress:progress];

    }
}

-(void) audioPlayerDidFinishPlaying:(AVAudioPlayer *)player successfully:(BOOL)flag
{
    if(flag)
    {
        [self.timer invalidate];
        self.audioPlayer.isPlayerPlaying = NO;
    }
}

我实现的唯一其他功能是暂停,因此当一个单元格在播放时被轻击时,播放器将暂停。再次点击它会从暂停的位置开始播放。

有人建议如何以正确的方式做这件事吗?我希望这会变得非常混乱。

编辑:尝试合并委托方法。

//Custom tableview cell class .h
@class OSAudioTableCell;
@protocol progressDelegate <NSObject>

-(float) trackProgress;

@end

@interface OSAudioTableCell : UITableViewCell <AVAudioPlayerDelegate>
{

}

@property (nonatomic, weak) id<progressDelegate> delegate;   

//Custom table view cell .m file
-(void) rowSelected2
{
        [self.waveView setProgress:[self.delegate trackProgress]];
}

-(void) prepareForReuse
{
    [super prepareForReuse];
    [self.timer invalidate];
    self.waveView.progress = 0;    
}

//view controller with tableview 
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
 {
             [((OSAudioTableCell*)[self.audioTable cellForRowAtIndexPath:indexPath]) rowSelected2];
             self.audioPlayer = [[OSTablePlayerController alloc] init];
             [self.audioPlayer playAudio:data];
             self.audioPlayer.isPlayerPlaying = YES;
             self.audioPlayer.playerTimer =[NSTimer timerWithTimeInterval:0.01 target:self selector:@selector(trackProgress:) userInfo:nil repeats:YES];
             [[NSRunLoop mainRunLoop] addTimer:self.audioPlayer.playerTimer forMode:NSRunLoopCommonModes];
}

-(float) trackProgress
{
    NSTimeInterval playTime = [self.audioPlayer currentTime];
    NSTimeInterval duration = [self.audioPlayer duration];

    float progress =  playTime/duration;

    if(!(self.audioPlayer.player.playing))
    {
        [self audioPlayerDidFinishPlaying:self.audioPlayer.player successfully:YES];

        progress = 0.00;
    }

    return progress;
 }

2 个答案:

答案 0 :(得分:0)

使用属性跟踪当前选择的单元格并播放音频。

使用属性selectedIndexPath。当您点击单元格时,使用当前点击的索引路径指定此属性。如果cellForRowAtIndexPath匹配,则selectedIndexPathselectedIndexPath与当前单元格进行比较比显示进度条其他隐藏所有不匹配的。

- (UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath

    // your other code
   if([selectedIndexPath isEqual:indexPath]){

      //allocate progressbar and start timer

   }
   else{
     //deallocate progressbar and invalidate timer
   }

}

您可以检查didSelectRowAtIndexPath selectedIndexPath是否等于当前点击单元格,如果是,则检查audioPlayer播放状态是否正在播放而不是暂停,否则重新开始播放

答案 1 :(得分:0)

在您的UITableViewCell子类中,您应该实现prepareForReuse。在此方法中,将单元格返回到其默认状态(与第一次初始化后的完全相同)。

然后,在cellForRowAtIndexPath:每次你将一个细胞出列时,它就会变得新鲜。只需将其配置为适合当前索引路径的项目。如果这是播放,更新并启动进度条的项目。如果不是,那就不要。

我认为你的一般问题是每个单元都维护着自己的计时器和音频播放器,但应该只有其中一个(在你的控制器中,不在你的单元子类中)。您的单元格是一个视图,因此应该尽可能愚蠢。它不应该知道它正在显示什么,或者当它被点击时会发生什么。它应该在点击时与控制器通信,控制器应该完成剩下的工作。