前言
简单实现弹幕功能,表跟我谈效率,但也有用队列控制同时弹的数量。
正文
代码实现:
let danmaku_speed: cgfloat = 150 // 弹幕每秒移动速度 let danmaku_space_time: nstimeinterval = 1 // 弹幕之间的时间间隔 let danmaku_max_row = 3 // 最多同时弹幕行数 let danmakufont = uifont.systemfontofsize(18) // 弹幕字体大小 var rowarray = array>(count: 3, repeatedvalue: array ()) var danmakuqueue = nsoperationqueue() // 队列 class danmaku : nsobject{ var msg: msg var view: uilabel? var size = cgsize(width: 0, height: 0) var row = 0 var starttime: nsdate? var duration: nstimeinterval = 0 var delay: nstimeinterval = 0 init(_ msg: msg, _ row: int, _ delay: nstimeinterval = 0) { self.msg = msg self.row = row self.delay = delay } } func queuedanmaku(msg: msg) { danmakuqueue.addoperation(nsblockoperation(block: { [weak self] in if let weakself = self { repeat { //检测放第几行 for var row = 0; row < weakself.danmaku_max_row; row { let rowdanmaku = weakself.rowarray[row] if rowdanmaku.count == 0 { let danmaku = danmaku(msg, weakself.danmakufont, row) weakself.rowarray[row].append(danmaku) self?.performselectoronmainthread("senddanmaku:", withobject: danmaku, waituntildone: true) return } else { if let lastdanmaku = rowdanmaku.last { if let starttime = lastdanmaku.starttime { let now = nsdate() let seconds = now.timeintervalsincedate(starttime) let widthduration = double(lastdanmaku.size.width / weakself.danmaku_speed) var delay = seconds - weakself.danmaku_space_time - widthduration if delay >= 0 { delay = 0 } else { if lastdanmaku.delay > lastdanmaku.duration { continue } } let danmaku = danmaku(msg, weakself.danmakufont, row, abs(delay) lastdanmaku.delay) weakself.rowarray[row].append(danmaku) self?.performselectoronmainthread("senddanmaku:", withobject: danmaku, waituntildone: true) return } } } } sleep(1000) } while self != nil } })) } func senddanmaku(danmaku: danmaku) { let text = "\(danmaku.msg.user_name) : \(danmaku.msg.text)" let size = nsstring(string: text).sizewithattributes([nsfontattributename : danmakufont]) let width = uiscreen.mainscreen().bounds.size.width let top = 54 danmaku.row * (int(size.height) 10) let label = uilabel(frame: cgrectmake(width, cgfloat(top), size.width, size.height)) let duration = (width size.width) / danmaku_speed danmaku.view = label danmaku.size = size danmaku.starttime = nsdate() danmaku.duration = nstimeinterval(duration) label.text = text label.font = danmakufont label.textcolor = uicolor.whitecolor() label.shadowcolor = uicolor.blackcolor() label.shadowoffset = cgsizemake(0, -1.0) self.view.addsubview(label) uiview.animatewithduration(double(duration), delay: danmaku.delay, options: uiviewanimationoptions.curvelinear, animations: { () -> void in label.left = -label.width }) { [weak self] (bool) -> void in if !(self?.rowarray[danmaku.row].isempty ?? true) { self?.rowarray[danmaku.row].removefirst() } label.removefromsuperview() } }
代码说明:
代码控制了最多同时只能弹三行,每行最后一条如果延迟大于跑弹幕的时间(已经有一条处于完全等待状态)就自动切到下一行,超过最大限制就等待。
* rowarray 主要用于查询前一个弹幕的位置和时间
* 别忘了在 deinit 里面加上 danmakuqueue.cancelalloperations()
* 注意 nsblockoperation 的 block 并不在主线程上
以上就是对ios开发 简单的弹幕功能的实现代码,有需要开发这种功能的朋友可以参考下。