单元格的进度条在其他单元格上重复

Cell's progress bar duplicates on other cells

我遇到了小区重用问题。

我所有的细胞都是一样的,只有一个部分。单元格包括标签、按钮和进度条。

按钮会触发声音(这是一个简单的 "play" 按钮)。当AVAudioPlayers委托方法被调用时,audioPlayerDidFinishPlaying:,我取消更新进度条的NSTimer,隐藏进度条,同时取消音频播放器。

所有这一切都发生在我的单元格 class 中,它继承自 UITableViewCell

一切正常,除了一件事:

播放声音时滚动会在新单元格上显示相同的进度条。

因此,如果我点击第二个单元格,滚动时显示的第二个下一个单元格将有一个向前移动的进度条(并在声音结束时停止+隐藏)。

我会向您展示我的自定义单元格 class,希望这对您有所帮助。我真的不知道如何解决这个问题。我在 cellForRow: 中尝试了 if 语句,但没有任何真正的成功。

@implementation SoundItemTableViewCell

- (void)awakeFromNib {
    // Initialization code
    self.progressBar.hidden = YES;
}

- (void)setSelected:(BOOL)selected animated:(BOOL)animated {
    [super setSelected:selected animated:animated];

    // Configure the view for the selected state
}

- (IBAction)playSound:(id)sender {

    [self.progressBar setProgress:0];
    self.progressBar.hidden = NO;

    NSString *filename = self.fileName;
    [self playSoundWithURL:[NSURL URLWithString:filename]];
}

- (void)playSoundWithURL:(NSURL*)url{


    NSError *error;
    if (self.audioPlayer){

        if(self.audioPlayer.playing){
            [self.audioPlayer stop];
        }
    }

    self.audioPlayer = [[AVAudioPlayer alloc]initWithContentsOfURL:url error:&error];
    self.audioPlayer.delegate = self;
    self.tmrProgress = [NSTimer scheduledTimerWithTimeInterval:0.1f target:self selector:@selector(updateElapsedTime) userInfo:nil repeats:YES];

    [self.audioPlayer prepareToPlay];
    [self.audioPlayer play];
    NSLog(@"Starting sound play with item : %@",url);

}

- (void)audioPlayerDidFinishPlaying:(AVAudioPlayer *)player successfully:(BOOL)flag{

    [self.progressBar setProgress:0 animated:YES];
    self.progressBar.hidden = YES;
    //self.progressBar = nil;
    [self.tmrProgress invalidate];
    self.tmrProgress = nil;
    player = nil;
    self.audioPlayer = nil;
    NSLog(@"Audio Finish");
}


- (void)updateElapsedTime{
    if (self.audioPlayer) {
        NSLog(@"Updating progress");
        [self.progressBar setProgress:[self.audioPlayer currentTime] / [self.audioPlayer duration]];
    }
}

表格视图。 pushList 是一个包含文件 URL 的数组

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
    static NSString *identifier = @"SoundItemTableViewCell";
    SoundItemTableViewCell *cell = [self.tbPushList dequeueReusableCellWithIdentifier:identifier];

    if (cell == nil) {
        cell = [[SoundItemTableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:identifier];
    }
    cell.fileName    = [pushList objectAtIndex:indexPath.row];
    cell.lbName.text = [[[pushList objectAtIndex:indexPath.row] lastPathComponent] stringByDeletingPathExtension];
    return cell;

}

我能做到的最好的办法是在进度条离开视图时隐藏它,因此其他进度条也不会显示,但是重新滚动到我的播放单元格会播放没有进度条的声音,这是 unsatisfactory/bad 用户体验行为。

确保在 cellForRowAtIndexPath: 中初始化单元格的所有属性。
由于您的细胞正在被回收,它们将保留其现有特性。

在行方法的table视图单元格中检查行是否被选中,如果未被选中则将进度条的进度设置为零..

问题是您正在重复使用音频播放器和周围的逻辑。你需要一些外部的东西来检查有问题的细胞是否是播放声音的细胞,你需要将控制器逻辑移到控制器中。

将此 属性 添加到您的视图控制器...

@property (nonatomic) NSString *playingFilename;

- (IBAction)playSound:(id)sender 移动到视图控制器中,并在 select 特定按钮时设置字符串...

- (IBAction)playSound:(id)sender {

    UIButton *playButton = sender;
    NSInteger index = playButton.tag;

    SoundItemTableViewCell *cell = (SoundItemTableViewCell *)[self.tbPushList cellForRowAtIndexPath:[NSIndexPath indexPathForRow:index inSection:0]];

    [cell.progressBar setProgress:0];
    cell.progressBar.hidden = NO;

    self.playingFilename = [pushList objectAtIndex:index];

    // Personally I'd move the playing logic into the controller as well... spin up as many audio players as you need... but they shouldn't be in the cell.
    [self playSoundWithURL:[NSURL URLWithString:self.playingFileName]];
}

然后

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

    static NSString *identifier = @"SoundItemTableViewCell";
    SoundItemTableViewCell *cell = [self.tbPushList dequeueReusableCellWithIdentifier:identifier];

    if (cell == nil) {
        cell = [[SoundItemTableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:identifier];
    }


   // tag your button.....
    cell.playButton.tag = indexPath.row;

    cell.lbName.text = [[[pushList objectAtIndex:indexPath.row] lastPathComponent] stringByDeletingPathExtension];

    // check to see if this index contains the right file
   BOOL isRightFile = ([self.playingFilename isEqualToString:[pushList objectAtIndex:indexPath.row]])

    cell.progressBar.hidden = !isRightFile;

    return cell;
}