项目中遇到一个tableView页面上的每一个cell中都有需要播放的音频文件,播放逻辑如下: cell离开页面时,保持播放;点击暂停或者播放其他音频文件,改音频文件停止.
大家都知道,iOS9.0以后<AVFoundation>框架下的AVPlayer用起来很方便.但是实际实现过程中,嵌套在tableView的cell重用过程中,就会出现如下问题:
1cell离开页面,停止播放;
2cell重用时,本没有播放的音频,进度条却随着在动;
3正在播放的cell音频离开页面,再次展示时,进度条不动了;
针对以上问题,我采取了如下解决方式:
1把AVPlayer放在Controller中来创建,播放某个cell中的音频时,更换Player的playItem;
2将cell中的播放按钮,进度条放在.h文件中,暴露出来便于Controller操作;
3cell的创建方式,不采用重用的方式,而是每次都重新创建;
在controller创建Player,对所有的Cell音频进行统一操控,便于实现不同音频的切换播放;将cell的控件暴露出来,在Controller中进行操作,能够对上次操作的音频文件,进行记录,然后在切换其他音频时,对记录的控件进行操作;不使用系统推荐的重用方式创建cell,能够避免cell重用时,控件没有按照默认的方式展现;
下面是具体代码:
//对cell的创建及对cell控件的记录
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
ZDTableViewCell *cell = [[ZDTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"ZDTableViewCell"];
cell.playBtn.tag = indexPath.row;
[cell.playBtn addTarget:self action:@selector(audioBtnClick:) forControlEvents:UIControlEventTouchUpInside];
[cell.slider addTarget:self action:@selector(sliderChanged:) forControlEvents:UIControlEventValueChanged];
if (indexPath.row == self.playingIndex) {
[cell.playBtn setImage:[UIImage imageNamed:@"home_audio_stop"] forState:UIControlStateNormal];
self.isAudioBreak = false;
self.slider = cell.slider;
self.audioPlayBtn = cell.playBtn;
self.currentTimeLabel = cell.currentTimeLabel;
self.totalTimeLabel = cell.totalTimeLabel;
}
return cell;
}
//对cell控件的统一指定方法
- (void)sliderChanged:(UISlider *)slider{
[self.audioPlayer playWithValue:slider.value];
}
- (void)audioBtnClick: (UIButton *)btn{
ZDTableViewCell *cell = [self.tableView cellForRowAtIndexPath:[NSIndexPath indexPathForRow:btn.tag inSection:0]];
NSString *songName = self.songNames[btn.tag];
self.currentTimeLabel = cell.currentTimeLabel;
self.totalTimeLabel = cell.totalTimeLabel;
if ((self.audioPlayBtn != btn)) {
self.playingIndex = btn.tag;
//修改UI
[self.audioPlayBtn setImage:[UIImage imageNamed:@"home_audio_play"] forState:UIControlStateNormal];
[btn setImage:[UIImage imageNamed:@"home_audio_stop"] forState:UIControlStateNormal];
//播放
cell.slider.userInteractionEnabled = true;
self.slider.userInteractionEnabled = false;
self.slider = cell.slider;
[self.audioPlayer playWithName: songName];
self.audioPlayBtn = btn;
self.isAudioBreak = false;
}else {
self.isAudioBreak = !self.isAudioBreak;
if (self.isAudioBreak) {
self.playingIndex = -1;
[self.audioPlayBtn setImage:[UIImage imageNamed:@"home_audio_play"] forState:UIControlStateNormal];
[self.audioPlayer pause];
self.slider.userInteractionEnabled = false;
}else{
self.playingIndex = btn.tag;
[self.audioPlayBtn setImage:[UIImage imageNamed:@"home_audio_stop"] forState:UIControlStateNormal];
[self.audioPlayer playWithName:songName];
self.slider.userInteractionEnabled = true;
}
}
}
对音频播放的Player进行了封装,其中音频的进度通过block代理的方式来实现.
git地址如下:
https://github.com/zhudong10/tableView-.git
网友评论
还是要重用,性能问题。
至于
>不使用系统推荐的重用方式创建cell,能够避免cell重用时,控件没有按照默认的方式展现;
则可以设置每个cell的状态为暂停状态(可以包括正在播放的cell,因为cell在即将呈现在屏幕上时就已经装在到tableView了,所以不怕播放按钮会被用户捕捉到状态不对)。业务处理类对播放音频进行刷帧(我是0.02秒更新一次progress),将progress和播放中cell对应的row传递给控制器,控制器通过tableView cellForRowAtIndexPath:可以得到一个cell,通过判断这个cell是否为空来断定cell是否处于屏幕上,如果是,则更新cell的progress值,如果false,则忽略。