【问题标题】:Cell's progress bar duplicates on other cells单元格的进度条在其他单元格上重复
【发布时间】:2015-08-07 20:28:23
【问题描述】:

我有一个单元重用问题。

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

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

所有这些都发生在我的单元格的类中,它继承自 UITableViewCell

一切正常,除了一件事:

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

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

我将向您展示我的自定义单元完整课程,希望这会有所帮助。我真的不知道如何解决这个问题。我在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;

}

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

【问题讨论】:

  • 你应该在你的单元类中实现 prepareForReuse 并关闭所有不再需要的东西。这在 dequeueReusableCellWithIdentifier 返回单元之前调用。

标签: ios uitableview progress-bar tableviewcell reuseidentifier


【解决方案1】:

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

【讨论】:

  • 你是指音频播放器之类的东西?这不会占用大量内存而没有潜在用途吗?
  • 不,这将需要大量的分配/解除分配,但这没关系。但问题是你的音频播放器是你手机的一部分。整个 tableViewController 应该只有一个音频播放器,否则滚动时播放会很麻烦。
  • 是的,现在我在单元格中创建了所有内容,视觉行为是完美的,但就像你说的,当滚动离开音频播放器时,我显然失去了声音。当按钮在我的单元格上但 URL/播放器在控制器中时,我应该如何只实现一个音频播放器?
  • 您可以使用按钮调用的方法来发送通知或调用 tableViewController 的方法来开始播放。然后,使用音频播放器的委托(tableViewController)发送一个通知,您的单元格将捕捉到以保持对播放状态的了解。
  • 你的回答救了我的命。
【解决方案2】:

问题是您正在重用您的音频播放器和周围的逻辑。您需要一些外部的东西来检查有问题的单元格是否是播放声音的单元格,并且您需要将控制器逻辑移动到控制器中。

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

@property (nonatomic) NSString *playingFilename;

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

- (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;
}

【讨论】:

  • 我之前尝试过,除了 isRightFile 布尔技巧。这很聪明,让我试一试:)
  • 是的,它有效。我只是在滚动和返回时遇到进度问题。进度条卡在 100% 并且不会消失。但我应该能够管理自己:) 谢谢 Magoo!
  • 没问题,祝你好运!
【解决方案3】:

在行方法的表格视图单元格中检查是否选择了行,如果没有选择,则将进度条的进度设置为零..

【讨论】:

  • 该行“从不”被选中,按下单元格内的按钮不会选择该单元格。我还有其他代码正在运行以进行单元格选择
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-01-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多