iOS仿網易雲音樂

前言

    最近作項目,遇到了須要播放網絡音頻的功能,因爲之前對於音頻方面的至少了解的不是不少,因而經過查閱資料對音頻方面作了一些學習,而後利用VLCKit仿照網易雲音樂的播放界面寫了個Demo,在此記錄一下,大神勿噴。git

    關於VLCKit,它是一款功能強大的全平臺播放器,幾乎支持全部格式的音頻、視頻文件的播放
集成方式
一、 按照wiki的說明去本身編譯:[wiki.videolan.org/iOSCompile]
二、cocoapods方式
經過pos search MobileVLCKit去搜索相關的庫,會發現有好幾個庫,我最終選擇了MobileVLCKit-unstable(由於這個庫更新的多,並且還在不時的更新)github

pod 'MobileVLCKit-unstable', '~> 3.0.0a42'複製代碼

說明

本Demo主要實現的有如下功能:正則表達式

* 播放網絡音頻、歌曲
* 唱片(播放時旋轉、左右滑動切換歌曲)
* 歌詞滾動、音量控制、歌曲切換
* 設置循環類型、上一曲、下一曲、喜歡歌曲等
* 鎖屏控制(播放、暫停、喜歡、上一曲、下一曲、播放條拖動)
* 耳機線控(播放、暫停、上一曲、下一曲、快進、快退)
* 通知監聽(插拔耳機、播放打斷)
* 支持AirPlay複製代碼

不足:數組

* 不能獲取緩衝進度(播放庫的問題)
* 不支持本地緩存(每次播放都須要網絡請求)複製代碼

demo中的音樂數據來自百度音樂,僅供學習使用,請勿在商業中使用緩存

實現

一、播放

demo中對VLCKit實現了二次封裝GKPlayer,主要實現的有播放、暫停、中止,以及播放狀態、進度、時間等的回調,這裏就不貼代碼了,具體可到Demo中查看GKPlayer。bash

二、轉盤

歌曲播放是須要實現轉盤無限旋轉的效果,這裏用到了CADisplayLink定時器不斷的刷新,而後經過設置視圖的transform來實現
首先建立CADisplayLink網絡

self.displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(animation)];
// 加入到主循環中
[self.displayLink addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode];複製代碼

監聽方法中改變視圖的transformide

self.diskView.transform = CGAffineTransformRotate(self.diskView.transform, M_PI_4 / 100);複製代碼

這樣就作到了視圖的無限旋轉,並且側滑返回的時候也不會中止,下面看看效果圖oop

轉盤旋轉
轉盤旋轉

轉盤左右滑動切換歌曲也比較簡單,用到了UIScrollView,而後再上面放了三個轉盤視圖,經過監聽UIScrollView的滾動來切換歌曲,看看效果圖吧。學習

轉盤滾動
轉盤滾動

三、歌詞

對於歌詞首先固然是解析歌詞了,經過換行符\n來分離每行的歌詞,而後再經過正則表達式,分離歌詞的時間與內容。

/**
 解析歌詞方法

 @param lyricString 歌詞對應的字符串
 @param isDelBlank  是否去掉空白行歌詞
 @return 歌詞解析後的模型數組
 */
+ (NSArray *)lyricParaseWithLyricString:(NSString *)lyricString isDelBlank:(BOOL)isDelBlank {
    // 1. 以\n分割歌詞
    NSArray *linesArray = [lyricString componentsSeparatedByString:@"\n"];

    // 2. 建立模型數組
    NSMutableArray *modelArray = [NSMutableArray new];

    // 3. 開始解析
    // 因爲有形如
    // [ti:若是沒有你]
    // [00:00.64]歌詞
    // [00:01.89][03:01.23][05:03.43]歌詞
    // [00:00.8]
    // 這樣的歌詞形式,因此最好的方法是用正則表達式匹配 [00:00.00] 來獲取時間

    for (NSString *line in linesArray) {
        // 正則表達式
        NSString *pattern = @"\\[[0-9][0-9]:[0-9][0-9].[0-9]{1,}\\]";

        NSRegularExpression *regular = [NSRegularExpression regularExpressionWithPattern:pattern options:NSRegularExpressionCaseInsensitive error:nil];
        // 進行匹配
        NSArray *matchesArray = [regular matchesInString:line options:NSMatchingReportProgress range:NSMakeRange(0, line.length)];

        // 獲取歌詞部分
        // 方法一
        //        NSTextCheckingResult *match = matchesArray.lastObject;
        //
        //        NSString *content = [line substringFromIndex:(match.range.location + match.range.length)];

        // 方法二  [00:01.78]歌詞
        NSString *content = [line componentsSeparatedByString:@"]"].lastObject;

        // 獲取時間部分[00:00.00]
        for (NSTextCheckingResult *match in matchesArray) {
            NSString *timeStr = [line substringWithRange:match.range];

            // 去掉開頭和結尾的[],獲得時間00:00.00

            // 去掉[
            timeStr = [timeStr substringFromIndex:1];
            // 去掉]
            timeStr = [timeStr substringToIndex:(timeStr.length - 1)];

            // 分、秒、毫秒
            NSString *minStr = [timeStr substringWithRange:NSMakeRange(0, 2)];
            NSString *secStr = [timeStr substringWithRange:NSMakeRange(3, 2)];

            // 因爲毫秒有一位或者兩位,因此應從小數點(第六位)後獲取
            NSString *mseStr = [timeStr substringFromIndex:6];

            // 轉換成以毫秒秒爲單位的時間 1秒 = 1000毫秒
            NSTimeInterval time = [minStr floatValue] * 60 * 1000 + [secStr floatValue] * 1000 + [mseStr floatValue];

            // 建立模型,賦值
            GKLyricModel *lyricModel = [GKLyricModel new];
            lyricModel.content      = content;
            lyricModel.msTime       = time;
            lyricModel.secTime      = time / 1000;
            lyricModel.timeString   = [GKTool timeStrWithMsTime:time];
            [modelArray addObject:lyricModel];
        }
    }

    // 去掉空白行歌詞
    if (isDelBlank) {
        [modelArray enumerateObjectsUsingBlock:^(GKLyricModel *obj, NSUInteger idx, BOOL * _Nonnull stop) {
            if (!obj.content || [obj.content isEqualToString:@""]) {
                [modelArray removeObject:obj];
            }
        }];
    }

    // 數組根據時間進行排序 時間(time)
    // ascending: 是否升序
    NSSortDescriptor *descriptor = [NSSortDescriptor sortDescriptorWithKey:@"msTime" ascending:YES];

    return [modelArray sortedArrayUsingDescriptors:@[descriptor]];
}複製代碼

而後就是歌曲播放是,滾動歌詞了,這裏經過在UITableView中先後都加上5行的空白行,讓歌詞可以顯示在中間,而後根據歌曲播放的時間,刷新tableview選中當前時間對應的歌詞並顯示在tableview的中間。

/**
 根據當前時間及總時間滾動歌詞

 @param currentTime 當前時間
 @param totalTime 總時間
 */
- (void)scrollLyricWithCurrentTime:(NSTimeInterval)currentTime totalTime:(NSTimeInterval)totalTime {
    if (self.lyrics.count == 0) self.lyricIndex = 0;

    for (NSInteger i = 0; i < self.lyrics.count; i++) {
        GKLyricModel *currentLyric = self.lyrics[i];
        GKLyricModel *nextLyric    = nil;

        if (i < self.lyrics.count - 1) {
            nextLyric = self.lyrics[i + 1];
        }

        if ((self.lyricIndex != i && currentTime > currentLyric.msTime) && (!nextLyric || currentTime < nextLyric.msTime)) {
            self.lyricIndex = i;

            //刷表
            [self.lyricTable reloadData];

            // 不是由拖拽產生的滾動,自動滾滾動歌詞
            if (!self.isScrolling) {

                NSIndexPath *indexPath = [NSIndexPath indexPathForRow:(self.lyricIndex + 5) inSection:0];

                [self.lyricTable selectRowAtIndexPath:indexPath animated:YES scrollPosition:UITableViewScrollPositionMiddle];
            }
        }
    }
}複製代碼

看看效果圖吧

歌詞
歌詞

其餘效果圖

鎖屏
鎖屏

固然還有不少的細節處理,在這裏就不在贅述了。具體實現仍是去看Demo吧。

小結

本demo中其實並無音視頻的底層的知識,只是作了對VLCKit的使用,界面也是徹底仿照網易雲音樂作的,這裏只是作一下分享,若是有寫的很差的地方還請見諒。

最後,若是您以爲還不錯,點個star吧!😁😁😁

github地址:GKAudioPlayerDemo

簡書地址:
iOS-VLCKit實現仿網易雲音樂播放音樂(一)

iOS-VLCKit實現仿網易雲音樂播放音樂(二)

iOS-VLCKit實現仿網易雲音樂播放音樂(三)

相關文章
相關標籤/搜索