iOS 彈幕實現分析及原理

彈幕需求

  • 彈幕在屏幕上以一定的軌道移動
  • 根據彈幕長度定移動速度
  • 彈幕文字支持自定義(字體、格式、顏色等)
  • 彈幕支持暫停及恢復

實現主要要解決的問題

  • 彈幕如何繪制?
  • 彈幕如何控制移動速度?
  • 彈幕如何檢測是否碰撞?
  • 彈幕如何暫停移動及恢復移動?

注:“彈幕碰撞”指彈幕移動過程中前一條展示與后一條展示不出現重疊。

根據已知的幾個問題,依次提出解決方案。

實現彈幕

彈幕如何繪制

Android 平臺DanmakuFlameMaster庫中,通過在 View 層的一幀幀的繪制來顯示彈幕。對于每一條來說,如果要實現彈幕的流暢性,需要保證每秒繪制的幀數處在一個較高的數字。如果出現大量的彈幕,同時繪制,對設備的性能要求也會很高。所以自定義繪制幀的方式,不一定適用于所有的設備。

除了自定義繪制幀的方式展示彈幕,還可以通過采用系統動畫的方式來實現彈幕文本的移動。例如 UIView 動畫、Facebook/pop 動畫。以系統 UIView 動畫為例:

[UIView animateWithDuration:duration delay:0 options:UIViewAnimationOptionCurveLinear animations:^{
        // bulletLabel 為彈幕內容 label
        bulletLabel.frame = CGRectMake(-bulletLabel.width, bulletLabel.y, bulletLabe.width, bulletLabel.height);
    } completion:^(BOOL finished) {
        //
}];

這樣實現了一個彈幕移動的過程。借助于系統 UIView 動畫,實現一個滾動過程中,開發者只需要關注動畫開始時間、持續時間、動畫開始執行的狀態和動畫結束執行的狀態,這里采用的 UILabel frame。具體的滾動動畫交于系統來負責,系統會根據設備的性能來調整來做對應的調整。

彈幕如何控制移動速度

首先根據文本的內容的屬性(字體、大?。┯嬎愠鑫谋撅@示后的 Width,line 為 1,根據 textWidth 及 screenWidth 來卻確定最終的 rate。

計算文本 width 可通過 boundingRect(with:options:attributes:context:)

彈幕如何檢測是否碰撞

檢測難點在于,怎么在彈幕滾動過程中檢測是否碰撞。彈幕的滾動過程中位于同一個 Y 的彈幕,新創建的彈幕顯示 frame 需要與正在滾動中的彈幕 frame 進行對照。如果新創建的彈幕滾動的過程中,不與正在滾動中的彈幕有視圖重疊。則新創建的彈幕以當前 frame 作為初始位置開始滾動。

那么兩者如何進行對照呢?

默認彈幕由右向左滾動,過程中,正在滾動中的彈幕位于左側,新建的彈幕位于右側。

如果正在滾動中的彈幕(記為 danmakuL)的開始時刻及結束時刻,彈幕視圖都沒有與新建彈幕(記為 danmakuR)視圖重合。那么新建彈幕在滾動過程中也不會與正在滾動中的彈幕有視圖重合的情況出現。

remainTime 代表著字幕存活時間,由于字幕的存活時間是由字幕的長度解決的。字幕越長,滾動過程中速度即越快。所以過程中已 danmakuL 與 danmakuR 間最小滾動時間(miniRemainTime)為標準,進行對比。如果在 miniRemainTime 內,danmakuL 與 danmakuR 之間沒有出現重合,那么整個過程中,彈幕也不會出現重合的情況。這樣就解決了彈幕碰撞的檢測。

演示代碼如下:

- (BOOL)checkIsWillHitWithWidth:(float)width danmakuL:(UILabel *)danmakuL danmakuR:(UILabel *)danmakuR {
    if (danmakuL.remainTime<=0) {
        return NO;
    }
    
    if (danmakuL.x + danmakuL.size.width > danmakuR.x) {
        return YES;
    }
    
    float minRemainTime = MIN(danmakuL.remainTime, danmakuR.remainTime);
    float xLeft = [danmakuL xWithScreenWidth:width remainTime:(danmakuL.remainTime - minRemainTime)];
    float xRight = [danmakuR xWithScreenWidth:width remainTime:(danmakuR.remainTime - minRemainTime)];
    if (xLeft + danmakuL.size.width > xRight) {
        return YES;
    }
    return NO;
}

彈幕如何暫停滾動及恢復滾動

在當前的實現過程中,彈幕滾動采用了 UIView 系統動畫。動畫暫停的基本原理是通過 View 的 presentationLayer 獲取 danmake 當前 frame 并作為彈幕暫停后的 frame,再移除 danmake 的 layer 動畫。同時記錄已滾動時間及當前 danmake frame。


// 暫停彈幕滾動
- (void)pauseDanmaku {
    
    CALayer *layer = danmaku.layer;
    CGRect rect = danmaku.frame;
    danmaku.label.frame = rect;
    [danmaku.label.layer removeAllAnimations];
}

// 開始滾動的方法與新建彈幕滾動方法相同,通過 UIView animation
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,967評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,273評論 3 415
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 175,870評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,742評論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,527評論 6 407
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,010評論 1 322
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,108評論 3 440
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,250評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,769評論 1 333
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,656評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,853評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,371評論 5 358
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,103評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,472評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,717評論 1 281
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,487評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,815評論 2 372

推薦閱讀更多精彩內容

  • 發現 關注 消息 iOS 第三方庫、插件、知名博客總結 作者大灰狼的小綿羊哥哥關注 2017.06.26 09:4...
    肇東周閱讀 12,151評論 4 61
  • 在iOS中隨處都可以看到絢麗的動畫效果,實現這些動畫的過程并不復雜,今天將帶大家一窺ios動畫全貌。在這里你可以看...
    每天刷兩次牙閱讀 8,541評論 6 30
  • 55.8kg
    早睡早起的習慣閱讀 124評論 0 0
  • 剛剛看完羅胖只是發布會,然后馬不停蹄的把我的感受寫下來。自從喬布斯開創商品發布會這個形式以來,知識發布會還是第一次...
    小城的卡夫卡閱讀 704評論 0 0
  • 有紀律的去做自己喜歡的事。 不要有捷徑。 不要聽信大眾的話。 甄別。 ~~~~ 2016.01.29. 有行動和改...
    孫曉曉曉閱讀 640評論 0 0