zoukankan      html  css  js  c++  java
  • 【Swift 2.0】实现简单弹幕功能

    前言

      简单实现弹幕功能,表跟我谈效率,但也有用队列控制同时弹的数量。

    声明
      欢迎转载,但请保留文章原始出处:)
      博客园:http://www.cnblogs.com
      农民伯伯: http://over140.cnblogs.com

    正文

        let DANMAKU_SPEED: CGFloat = 150    // 弹幕每秒移动速度
        let DANMAKU_SPACE_TIME: NSTimeInterval = 1    // 弹幕之间的时间间隔
        let DANMAKU_MAX_ROW = 3    // 最多同时弹幕行数
        let danmakuFont = UIFont.systemFontOfSize(18)    // 弹幕字体大小
        var rowArray = Array<Array<Danmaku>>(count: 3, repeatedValue: Array<Danmaku>())    
        var danmakuQueue = NSOperationQueue()    // 队列
    
        class Danmaku : NSObject{
            var msg: Msg
            var view: UILabel?
            var size = CGSize( 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 并不在主线程上

  • 相关阅读:
    RedGlove 权限管理系统(1)权限概述
    SPQuery查询语法简要说明
    DataGridView使用技巧大全
    实战asp.net MVC+ADO.NET EntityFramework
    RedGlove 权限管理系统(2)功能模块设计
    C# 如果何从线程中操作控件
    PageHelper 类 和 ValidateHelper 类
    字符串帮助类
    XMLHelper 类
    Android中截取当前屏幕的功能
  • 原文地址:https://www.cnblogs.com/over140/p/4861347.html
Copyright © 2011-2022 走看看