Индикатор выполнения ячейки дублируется на других ячейках
У меня есть проблема повторного использования клетки.
Все мои клетки идентичны, есть только один раздел. Ячейки включают метку, кнопку и индикатор выполнения.
Кнопка запускает звук (это простая кнопка воспроизведения). Когда вызывается метод делегата AVAudioPlayers, audioPlayerDidFinishPlaying:
Я аннулирую NSTimer
это обновляет индикатор выполнения, скрывает индикатор выполнения, а также обнуляет аудиоплеер.
Все это происходит в классе моей клетки, которая наследует от UITableViewCell
,
Все работает как надо, кроме одного:
Прокрутка во время воспроизведения звука показывает тот же индикатор выполнения на новых ячейках.
Поэтому, если я коснусь, скажем, второй ячейки, вторая следующая ячейка, отображаемая при прокрутке, будет иметь индикатор выполнения, перемещающийся вперед (и остановка + скрытие, когда звук закончится).
Я покажу вам мой класс, полный класс, надеюсь, это поможет. Я действительно не знаю, как это исправить. Я попробовал if-заявления в cellForRow:
но без какого-либо реального успеха.
@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;
}
Лучшее, чего я мог добиться, - это скрыть индикатор выполнения, когда он выходит из поля зрения, и поэтому никакой другой индикатор выполнения также не показывался бы, но при повторной прокрутке к моей игровой ячейке будет воспроизводиться звук без индикатора выполнения, что является неудовлетворительным / плохим UX поведение.
3 ответа
Проблема в том, что вы повторно используете свой аудиоплеер и окружающую логику. Вам нужно что-то внешнее, чтобы проверить, является ли рассматриваемая ячейка воспроизводящей звук, и вам нужно переместить логику контроллера в контроллер.
Добавьте это свойство к вашему контроллеру представления...
@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;
}
Обязательно инициализируйте ВСЕ свойства вашей ячейки в cellForRowAtIndexPath:
,
Поскольку ваши клетки перерабатываются, они сохранят свои существующие свойства.
В ячейке табличного представления для метода строки проверьте, выбрана ли строка или нет, а затем установите индикатор выполнения на ноль.