iOS彈幕組件LNDanmakuMaster

LNDanmakuMaster是一個輕量的彈幕播放器,通過:創(chuàng)建播放器->創(chuàng)建軌道->添加彈幕的方式進(jìn)行彈幕播放,提供豐富軌道樣式的同時也支持自定義軌道;對傳入的彈幕的視圖層沒有要求(任意的View/Layer);提供多種(目前是3)彈幕分布策略;支持使用軌道組播放特殊彈幕;提供與分布策略的對應(yīng)的彈幕seek策略。
Github鏈接:LNDanmakuMaster
  • 你可以直接下載這個鏈接并運(yùn)行上面豐富的Demo,或參考Demo代碼實(shí)現(xiàn)自己的彈幕播放器,也可以直接使用Cocoapods??
Cocoapods
pod 'LNDanmakuMaster'
子文檔

0.iOS端彈幕相關(guān)調(diào)研
1.從一個彈幕開始:LNDanmakuAttributes
2.動畫的核心:LNDanmakuTrackController
3.暫存和分發(fā):LNDanmakuDispatcher
4.彈幕復(fù)用:LNDanmakuPool
5.彈幕容器和手勢:LNDanmakuContainerView
6.處理?xiàng)l件彈幕:LNDanmakuTrackGroup
7.封裝組件:LNDanmakuPlayer

彈幕機(jī)制
  1. 驅(qū)動機(jī)制
    視頻播放器的刷新率通常為29frame/s,彈幕播放器采用同樣的刷新頻率會有卡頓感,因此彈幕播放器通常使用自己的刷新驅(qū)動,要么是UIView animation,要么是CADisplayLink;CADisplaylink支持更多的細(xì)節(jié)、進(jìn)度控制,因此這里我們選用的是CADisplayLink。
    LNDanmakuClock是這樣一個驅(qū)動,封裝了CADisplayLink,增加了一些暫停、銷毀的控制方法,這個時鐘每次的輸出就是從上一次DisplayLink回調(diào)到這次displayLink回調(diào)的一小段時間。
  2. 進(jìn)度控制機(jī)制
    LNDanmakuMaster整體采用時間定義進(jìn)度,這也是它與其他彈幕框架的主要區(qū)別之一,我們的所有進(jìn)度控制、追趕控制、繁忙度控制,都是使用時間計(jì)算的。
    使用時間變量替代空間變量的優(yōu)勢包括:
  • 如果你的軌道路線并非直線:如果你希望一個彈幕既可以在水平軌道播放也可以在圓形軌道播放,既要給出角速度,也要給出線速度,如果使用時間單位,只需要給出運(yùn)行的總時間。
  • 如果你先控制一個曲線軌道兩條彈幕之間的間距,空間間距需要計(jì)算曲線的長度,而對時間間距來說處理起來就和直線一樣。
  • 在做一些判斷時,如果使用空間條件做判斷,則需要進(jìn)行速度、時間相關(guān)大量乘除法運(yùn)算,使用時間可能只需要加減法,雖然我不知道具體是否有優(yōu)勢,但直觀上感覺乘除法是沒有加減法快的。
  • 如果是像B站那種中間出現(xiàn)一列的彈幕,它不需要速度,只需要顯示的時間就夠了。
    總之,使用時間體系替代速度體系,是能統(tǒng)一多種軌道進(jìn)度控制的一個好方法。

3.刷新機(jī)制
根據(jù)Clock的輸出,我們可以得到一個穩(wěn)定的回調(diào)得知剛剛經(jīng)過了多長一段時間,那么彈幕的刷新過程就成為:在彈幕的剩余存活時間中扣除剛剛經(jīng)過的那段時間,并根據(jù)扣除后的剩余時間占總時間的百分比來刷新彈幕的位置、大小等信息。
經(jīng)過以上三個主要機(jī)制的介紹,已經(jīng)有了實(shí)現(xiàn)一個彈幕框架的所有主要邏輯,剩下的就是一些模塊的細(xì)分和細(xì)節(jié)上的雕琢。

模塊分工

LNDanmakuMaster將整個彈幕框架分成以下幾個部分(Abstract代表支持重寫定制):

模塊名稱 類名 備注
播放器 LNDanmakuPlayer 播放器相當(dāng)于對整個彈幕框架其他組件的整合,對外提供調(diào)用方法和時機(jī)代理
分發(fā)器 LNDanmakuAbstractDispatcher Dispatcher類似管理軌道的工頭兒,根據(jù)軌道集合的狀態(tài)決定彈幕放到哪里才是最好的
軌道控制器 LNDanmakuAbstractTrackController 軌道控制器類似一個工人,定期使用工具(Track)維護(hù)自己的彈幕,并向Dispatcher反饋?zhàn)约旱模ǚ泵?空閑)狀態(tài)
軌道 LNDanmakuAbstractTrack Track的職責(zé)完全符合軌道的定義,它不維護(hù)彈幕,只維護(hù)任意一條彈幕彈幕在這個軌道上的刷新的位置、大小、仿射變換等屬性與時間進(jìn)度的映射,像是一個空間信息與時間信息的函數(shù)
樣式 LNDanmakuAbstractAttributes 樣式是彈幕的載體,包含了一條彈幕的所有信息,例如:存活時間、位置、攜帶的業(yè)務(wù)模型、展示時使用的View/Layer等等。對,沒錯,與CollectionViewAttributes十分類似,并根據(jù)播放器特性增加了時間戳信息

額外的組件

模塊名稱 類名 備注
軌道組 LNDanmakuTrackGroup 這個組件是用來做一些特殊彈幕播放的,是類似一個Player的更小單元(但沒有自己的驅(qū)動),內(nèi)部包含了一個Dispatcher和若干TrackController

這個組件的意義:
某些彈幕播放對軌道有一定的要求,又或是軌道對自己播放的彈幕有一定要求,例如:送禮物的軌道只能出現(xiàn)在屏幕頂端,而不是中央,來避免影響用戶觀看視頻;或者是,圓形的軌道不能那些較長的文字,這樣它看起來就不是那么圓了,等等。
一但從兩個方面考慮這個問題,就會陷入:軌道挑選彈幕/彈幕挑選軌道的困境,而實(shí)際上兩種情況是都存在的,這兩個問題最后統(tǒng)一使用軌道組解決,用戶指定一個軌道的分組,并可以跨過Player層,直接向這個軌道組拋彈幕,那么這個彈幕就只有可能出現(xiàn)在這個軌道組包含的軌道中;這個功能在Demo中一個彩虹樣式的軌道中得以體現(xiàn),我將七種顏色的彈幕分別拋入七個軌道組中(每個軌道組有三根軌道,兩個相鄰的軌道組公用中間那個重合的軌道),這樣它們就呈現(xiàn)除了一種彩虹的效果。

使用示例

以上介紹完了這個框架的所有重要組件,這里舉例介紹構(gòu)建一個最簡單彈幕播放器的過程:
1.懶加載一個danmakuPlayer:
這個是起碼要做,不需要做任何配置它就可以正常工作

- (LNDanmakuPlayer *)danmakuPlayer
{
    if (!_danmakuPlayer) {
        _danmakuPlayer = [[LNDanmakuPlayer alloc] init];
    }
    return _danmakuPlayer;
}

2.把這個播放器的容器View加到屏幕上:

    [self.view addSubview:self.danmakuPlayer.containerView];

3.給這個Player加一些軌道:
Player支持自定義就是主要體現(xiàn)在自定義軌道和彈幕樣式上,所以,所有的軌道都是你親手加上去的,你可以在init/viewDidLoad等初始化的時機(jī)做這個時,也可以在Player懶加載時一并加好

- (void)addTrack
    for (int i = 0; i < 20; i++) {
        LNDanmakuHorizontalMoveTrackController *horizontalTrackController = [[LNDanmakuHorizontalMoveTrackController alloc] init];
        horizontalTrackController.horizontalTrack.startPosition = CGPointMake(0, 44.f + 30.f * i);
        horizontalTrackController.horizontalTrack.width = self.view.frame.size.width;
        horizontalTrackController.spaceTimeInterval = 0.f;
        [self.danmakuPlayer addTrack:horizontalTrackController];
    }
}

4.讓播放器動起來!
現(xiàn)在這個播放器就可以從外界接口隨便一個彈幕并播放在屏幕上了

- (void)startPlay {
    [self.danmakuPlayer start];
}

5.讓我們嘗試放一個簡單的彈幕放上去:

  • (void)addRandomDanmaku
    {
    LNDanmakuAttributes *attributes = [[LNDanmakuAttributes alloc] init];
    UIView *colorView = [[UIView alloc] init];
    colorView.backgroundColor = [UIColor redColor];
    attributes.presentView = colorView;
    attributes.trackTime =4.f;
    attributes.size = CGSizeMake(88.f, 44.f);
    [_player insertAttributes:@[attributes]];
    }

這個框架盡量使用最符合正常邏輯的方法定義了每個組件的分工來保證它使用起來是最舒服的,并盡可能封裝了那些看起來比較復(fù)雜的邏輯:分發(fā)、刷新、追趕等等;當(dāng)然,我覺得一個合理的框架應(yīng)該是下限很低,上限也很高的,而不是一成不變使用規(guī)則(正如掌控疾風(fēng)的某位男子應(yīng)該算得上是設(shè)計(jì)得比較成功的角色),所以,當(dāng)使用者需要深入探討這些邏輯的時候,也可以從外部輕易定制他們,玩出自己的特色。

后續(xù)會陸續(xù)更新一些使用上或是原理方面的文章介紹這個框架,雖然實(shí)現(xiàn)起來沒有很多高超的技巧,但我認(rèn)為代碼優(yōu)秀與否并非取決于使用了多么高深或是精妙的語言特性,而是寫代碼的邏輯和思路;而且,我從心底十分抵制那些沒什么復(fù)雜邏輯卻要制定很多使用規(guī)則的組件(更惡心的是還要業(yè)務(wù)線強(qiáng)推),所以這個組件一定會朝著盡量少的使用規(guī)則、盡量樸素的代碼、更豐富的功能方向發(fā)展。

最后附上幾個Demo中的效果圖

  • 橫向的軌道

  • pop動畫軌道

  • 波浪軌道+軌道分組

  • 心形軌道

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,622評論 6 544
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 99,716評論 3 429
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,746評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,991評論 1 318
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 72,706評論 6 413
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 56,036評論 1 329
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 44,029評論 3 450
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 43,203評論 0 290
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 49,725評論 1 336
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 41,451評論 3 361
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 43,677評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,161評論 5 365
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,857評論 3 351
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,266評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,606評論 1 295
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,407評論 3 400
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 48,643評論 2 380

推薦閱讀更多精彩內(nèi)容