自定义 tableviewcell 上的 UISlider 和 UILabel 在第二次播放音频之前不会使用 avaudioplayer 更新
Posted
技术标签:
【中文标题】自定义 tableviewcell 上的 UISlider 和 UILabel 在第二次播放音频之前不会使用 avaudioplayer 更新【英文标题】:UISlider & UILabels on custom tableviewcell not updating with avaudioplayer until audio is played a second time 【发布时间】:2017-08-13 14:45:57 【问题描述】:背景:我有一个 UITableView,它最初会加载一些标准的 UITableViewCell。单击其中一个时,会重新加载表格,但单击的单元格会变成一个名为“RecordingTableCell”的自定义子类,它有 2 个 UILabel、一个 UIButton 和一个 UISlider。目前这工作正常。
按下按钮时,会设置一个 AVAudioPlayer 并播放一个声音文件。但是,执行此操作的方法 ([self setupAudio]
) 还会获取 2 个 UILabel 和 UISlider,以便它们可以随着音频的进度进行更新(我不确定我是否以正确的方式获取它们)。
第一次按下播放按钮时,会播放音频,但滑块或标签根本不会改变。但是,在音频完成后(即一旦调用 audioPlayerDidFinishPlaying),如果再次按下播放按钮,一切都会正常运行。
这里是代码:(对不起大块!)
...
-(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];
我尝试移动一些位,但我不确定在 [self setupAudio] 中获取“RecordingTableCell”子视图是否出错,或者是否是音频设置错误播放器。
任何帮助将不胜感激!
【问题讨论】:
【参考方案1】:我认为播放器的当前/duration时间是double类型,可以通过以下方法获取为字符串:
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])
当前时间字符串:
func getCurrentTimeAsString() -> String
guard let time = player?.currentTime else
return "00:00"
return getTimeString(from: time)
总时间字符串:
func getDurationAsString() -> String
guard let time = player?.duration else
return "00:00"
return getTimeString(from: time)
获取过程价值:
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)
而且你需要使用定时器来更新当前的时间标签文本,不要忘记停止定时器。
timer = Timer.scheduledTimer(withTimeInterval: 0.5, repeats: true, block: [unowned self] (timer:Timer) in
self.updateUIWithTimer()
)
func updateUIWithTimer()
currentTimeLabel.text = getCurrentTimeAsString()
timeSlider.value = getProgressValue()
【讨论】:
感谢您的回复 (+1),我已经在 Swift 中测试了您的代码,它可以自行运行,但是,当将其合并到我的原始 objc 中时,我仍然会遇到同样的错误UISlider & UILabels 只在第二次播放后响应。【参考方案2】:我不太确定这是否是正确的解决方法(即,我可能在这里遗漏了一些更基本的东西),但我设法通过创建一个布尔变量来保存它是否解决了这个问题是第一次设置AVAudioPlayer进行录音,如果是在actionButtonPressed
方法中,重新实例化子视图。
【讨论】:
以上是关于自定义 tableviewcell 上的 UISlider 和 UILabel 在第二次播放音频之前不会使用 avaudioplayer 更新的主要内容,如果未能解决你的问题,请参考以下文章
自定义 TableViewCell 的 UIImageView 出口 nil
从 TableViewCell 上的 UITextField 获取文本