實現如下:
需要的數據源:
1、demo.mp3:音頻文件
2、samplePoints 數組:每秒音量(0-1)數組,根據音頻pcm採樣數據文件計算出來的(遍歷:每秒取一點,並記錄下最大值;最後按取值爲0至1,進行縮放。計算完的數存如數組)
(這裏不過多描述計算音量過程,以後有時間補...)
接下來是UI實現思路:
一、滑動視圖:
用了兩個TableView,上面的顯示時間和刻度,下面的顯示音量Lines。
爲了讓時間顯示在cell中間,所以設置結構如下圖:
time tableView 不可滑動,Wave tableView的 scrollViewDidScroll 回調裏設置time tableView的偏移量,使其保持一致。
二、數據處理
根據上面UI結構,所以第一個cell只有10s的數據,而後開始每個cell畫30s,直到最後一個有多少畫多少
// 因爲時間刻度顯示問題,爲了把label放在中間,所以第一個section左邊空出了10s,每個section畫30s的數據
// 刻度的每個間隔是2s,也就是需要可以畫2條線(kAudioPlayerLineSpacing:每條線的間距;每個刻度的就*2)
- (void)setPoints:(NSArray *)points {
_points = points;
NSMutableArray *tempArray = [NSMutableArray arrayWithArray:_points];
self.pointArrays = [[NSMutableArray alloc] init];
NSInteger index = 0;
while (tempArray.count > 0) {
if (index == 0) {
if (tempArray.count >= 20) { // section0 數據
[self.pointArrays addObject:[tempArray subarrayWithRange:NSMakeRange(0, 20)]];
[tempArray removeObjectsInRange:NSMakeRange(0, 20)];
}
} else {
if (tempArray.count >= 30) {
[self.pointArrays addObject:[tempArray subarrayWithRange:NSMakeRange(0, 30)]];
[tempArray removeObjectsInRange:NSMakeRange(0, 30)];
} else {
[self.pointArrays addObject:[tempArray copy]];
[tempArray removeAllObjects];
}
}
index++;
}
self.timeView.points = self.pointArrays;
self.waveView.points = self.pointArrays;
}
三、播放器
AVPlayer:通過`addPeriodicTimeObserverForInterval:queue:usingBlock:`實現每秒回調,監聽播放進度
_player = [[AVPlayer alloc] initWithURL:self.playURL];
__weak typeof(self) weakSelf = self;
[_player addPeriodicTimeObserverForInterval:CMTimeMake(1.0, 1.0) queue:dispatch_get_main_queue() usingBlock:^(CMTime time) {
float currentTime = weakSelf.player.currentTime.value / weakSelf.player.currentTime.timescale;
[weakSelf.waveView setContentOffset:CGPointMake(0, currentTime * kAudioPlayerLineSpacing)];
}];
kAudioPlayerLineSpacing:是每條Line之間的距離(可以隨意設置)
所以每個刻度的間距就是:kAudioPlayerLineSpacing * 2 (因爲個刻度表示2s)
四、滑動控制播放進度
1、首先去掉tableView的滑動慣性,否則滑動出界就很難控制
在 scrollViewWillBeginDecelerating: 開始減速方法裏設置 [scrollView setContentOffset: animated:NO]
(設置偏移爲手指滑動到的位置,並不需要滑動動畫,即可去掉滑動慣性)
2、然後滑動的時候需要暫停player,否則就會跟 TimeObserver 回調裏設置的偏移 衝突
在 scrollViewWillBeginDragging: 方法裏調用 [_player pause]
在 scrollViewDidEndDragging: 方法里根據 偏移 和 kAudioPlayerLineSpacing 計算出需要播放的時間(秒數),
- (void)didEndDraggingY:(CGFloat)y {
// 拖拽結束後,根據偏移計算時間,設置播放進度
CGFloat second = y / kAudioPlayerLineSpacing;
[self.player seekToTime:CMTimeMakeWithSeconds(second, NSEC_PER_SEC)];
if (self.playBtn.selected) { // 如果是播放狀態則開始播放
[self.player play];
}
}