美文网首页
礼物通道

礼物通道

作者: br_MorningStar | 来源:发表于2017-11-27 00:02 被阅读24次

直播礼物动画

  • 1礼物展示的View
  • 礼物展示View上需要!通道

创建所需要的View

GiftContainerView.swift 展示礼物的View
GiftChannelView.swift 通道View
GiftModel.swift 通道所需要的Model
GiftDigitLabel.swift自定义Label

  • 1.自定义GiftDigitLabel
    * 有描边效果
    * 画两次文字
    * 需要执行动画(弹动)
  • 2.自定义GiftChannelView
    * 使用Xib描述View
    * 定义模型GiftModel
    * 开始执行弹动动画(从左侧弹出来)
    * 开始执行GiftDigitLabel动画
    * 延迟三秒钟,执行消失动画
    * 定义一个外界也可添加缓存方法:如果是正在登台消失,则执行执行GiftDigitLabel弹动动画/添加到缓存中
    * 需要给ChannelView定义状态
    * 给状态进行赋值
  • 3定义GiftCintainerView
    * 给GiftCintainerView添加ChannelView
    * 让外界可以给我传入模型
    * 检测是否有正执行动画ChannelView和新传入的模型师userName/giftName相同
    * 检测是有限制的ChannelView
    * 将模型添加到缓存中
    * 监听ChannelView的动画完成回调,判断缓存中是否有内容,从缓存中取出所有相同内存,继续执行动画

1.自定义Label设置以及接口

重写drawText方法绘制描边

override func drawText(in rect: CGRect) {
        //获取上下文
        let context = UIGraphicsGetCurrentContext()
        
        //2给上下文线段设置一个宽度,通过该宽度话出文本
        context?.setLineWidth(5)
        context?.setLineJoin(.round)    //添加模式 .round 圆角线
        context?.setTextDrawingMode(.stroke)
        textColor = UIColor.orange
        super.drawText(in: rect)
        
        context?.setTextDrawingMode(.fill)
        textColor = UIColor.white
        super.drawText(in: rect)
    }

编写动画开始接口

func showDigitAnimation( _ complection : @escaping() -> () ){
        
        UIView.animateKeyframes(withDuration: 0.25, delay: 0, options: [], animations: {
            
            //一 开始时间 ,二 执行时长 0.25的 0.5倍
            UIView.addKeyframe(withRelativeStartTime: 0.0, relativeDuration: 0.5, animations: {
                self.transform = CGAffineTransform(scaleX: 3.0, y: 3.0)
            })
            
            UIView.addKeyframe(withRelativeStartTime: 0.5, relativeDuration: 0.5, animations: {
                self.transform = CGAffineTransform(scaleX: 0.7, y: 0.7)
            })
            
        }) { (isFinished) in
            UIView.animate(withDuration: 0.25, delay: 0, usingSpringWithDamping: 0.4, initialSpringVelocity: 10, options: [], animations: {
                self.transform = CGAffineTransform.identity
            }, completion: { (inFinished) in
                complection()
            })
        }
        
        /*
        UIView.animate(withDuration: 0.1, animations: {
            self.transform = CGAffineTransform(scaleX: 3.0, y: 3.0)
        }) { (inFinished) in
            UIView.animate(withDuration: 0.1, animations: {
                self.transform = CGAffineTransform(scaleX: 0.7, y: 0.7)
            }, completion: { (inFinished) in
                UIView.animate(withDuration: 0.25, delay: 0, usingSpringWithDamping: 0.4, initialSpringVelocity: 10, options: [], animations: {
                    self.transform = CGAffineTransform.identity
                }, completion: { (inFinished) in
                    complection()
                })
            })
        }
    */
    }

2.创建GiftModel

class GiftModel: NSObject {
    var senderName : String = ""    // 谁送的礼物 (谁)
    var senderURL : String = ""     //头像 (谁)
    var giftName : String = ""      //礼物名
    var giftURL : String = ""       //礼物URL
    
    init(senderName : String ,senderURL : String ,giftName :String ,giftURL : String) {
        self.senderName = senderName
        self.senderURL = senderURL
        self.giftName = giftName
        self.giftURL = giftURL
    }
    
    override func isEqual(_ object: Any?) -> Bool {
        guard let objec = object as? GiftModel else { return false }
        
        guard objec.giftName == giftName && objec.senderName == senderName else { return false }
        
        return true
    }
}

3.编写GiftChannelView代码(通道)

大致思路
给GiftChannelView 设置Model 利用Model的didSet方法监听礼物的改变进行礼物连击动画

设置状态

enum GiftChannelViewState {
    case idle   //闲置状态
    case animating  //正在执行动画
    case willEnd    //正在等待
    case endAnimating //正在消失动画
}

设置属性以及监听礼物的改变

class GiftChannelView: UIView {

    // MARK: 控件属性
    @IBOutlet weak var bgView: UIView!
    @IBOutlet weak var iconImageView: UIImageView!
    @IBOutlet weak var senderLabel: UILabel!
    @IBOutlet weak var giftDescLabel: UILabel!
    @IBOutlet weak var giftImageView: UIImageView!
    @IBOutlet weak var digitLabel: GiftDigitLabel!
    
    fileprivate var cacheNumber : Int = 0   //缓存 计数
    fileprivate var currentNumber : Int = 0     //当前连击数
    var state : GiftChannelViewState = .idle
    
    /*参数 返回值 */
    /*var complectionCallback : ) -> Void 保证初始化所以是Optional*/
    /*var complectionCallback : ((channel : GiftChannelView) ->Void)? 3.0不能写外部参数*/
    var complectionCallback : ((GiftChannelView) ->Void)?
    
    var giftModel : GiftModel? {
        didSet{
            //1对模型校验
            guard let giftModel = giftModel else { return }
            //2给空间设置 数据
            iconImageView.image = UIImage(named:giftModel.senderURL)
            senderLabel.text = giftModel.senderName
            giftDescLabel.text = "送出礼物: 【\(giftModel.giftName)】"
            giftImageView.image = UIImage(named : giftModel.giftURL)
            
            //将ChannelView弹出
            state = .animating
            performAnimation()
        }
    }
}

设置UI

extension GiftChannelView {
    override func layoutSubviews() {
        super.layoutSubviews()
        
        bgView.layer.cornerRadius = frame.height * 0.5
        iconImageView.layer.cornerRadius = frame.height * 0.5
        bgView.layer.masksToBounds = true
        iconImageView.layer.masksToBounds = true
        iconImageView.layer.borderWidth = 1
        iconImageView.layer.borderColor = UIColor.green.cgColor
    }
}

动画

// MARK: - 动画
extension GiftChannelView {
    // MARK: - 弹出动画
    fileprivate func performAnimation(){
        digitLabel.alpha = 1.0
        digitLabel.text = " x1 "
        UIView.animate(withDuration: 0.25, animations: {
            self.alpha = 1.0
            self.frame.origin.x = 0
        }) { (isFinished) in
            self.performDigitAnimation()
        }
    }
    // MARK: - 连击动画
    fileprivate func performDigitAnimation(){
        currentNumber += 1
        digitLabel.text = " x\(currentNumber) "
        digitLabel.showDigitAnimation {
            
            if self.cacheNumber > 0 {
                self.cacheNumber -= 1
                self.performAnimation() //递归调用
            }else{
                self.state = .willEnd
                self.perform(#selector(self.performEndAnimation), with: self, afterDelay: 3)
            }
        }
    }
// MARK: - 消失动画
   @objc fileprivate func performEndAnimation(){
    state = .endAnimating
    UIView.animate(withDuration: 0.25, animations: {
        self.frame.origin.x = UIScreen.main.bounds.width
        self.alpha = 0
    }) { (isFinished) in
        self.giftModel = nil
        self.frame.origin.x = -self.frame.width
        self.state = .idle
        self.currentNumber = 0
        self.cacheNumber = 0
        self.digitLabel.alpha = 0.0
        /*
        //block调用*/
        if let complectionCallback = self.complectionCallback{
            complectionCallback(self)
        }
 
        
    }
    }
}

对外提供的方法

extension GiftChannelView {
    func addOnceToCache(){
        
        if state == .willEnd{
            performDigitAnimation()
            //取消之前的任务3秒等待
            NSObject.cancelPreviousPerformRequests(withTarget: self)
        }else{
            cacheNumber += 1
        }
    }

    class func loadChannelView() -> GiftChannelView{
        return Bundle.main.loadNibNamed("GiftChannelView", owner: nil, options: nil)?.first as! GiftChannelView
    }
}

4编写GiftContainerView代码(最外面的View)

属性

private let kChannelCount = 2
private let kChannelViewH : CGFloat = 40
private let kChannelMargin : CGFloat = 10

class GiftContainerView: UIView {
    
    fileprivate lazy var channelViews : [GiftChannelView] = [GiftChannelView]()
    fileprivate lazy var cacheGiftModels : [GiftModel] = [GiftModel]()   //缓存中的Model
    
    override init(frame: CGRect) {
        super.init(frame: frame)
        setupUI()
    }
    
    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
}

UI设置

extension GiftContainerView{
    fileprivate func setupUI(){
        //1根据当前的取代数,创建ChannelView
        let w : CGFloat = frame.width
        let h : CGFloat = kChannelViewH
        let x : CGFloat = 0
        for i in 0..<kChannelCount {
            let y : CGFloat = (h + kChannelMargin) * CGFloat(i)
            
            let channelView = GiftChannelView.loadChannelView()
            channelView.frame = CGRect(x: x, y: y, width: w, height: h)
            channelView.alpha = 0.0
            channelView.state = .idle
            //            channelView.delegate = self
            channelViews.append(channelView)
            addSubview(channelView)
            
            
            channelView.complectionCallback = { channelView in
                // 取出缓存中的Model第一个
                guard self.cacheGiftModels.count != 0 else { return }
                let firstGiftModel = self.cacheGiftModels.first!
                self.cacheGiftModels.removeFirst()
                channelView.giftModel = firstGiftModel
                
                // .将数组中剩余有和firstGiftModel相同的模型放入到ChanelView缓存中
                for i in (0..<self.cacheGiftModels.count).reversed() {
                    let giftModel = self.cacheGiftModels[i]
                    if giftModel.isEqual(firstGiftModel) {
                        channelView.addOnceToCache()
                        self.cacheGiftModels.remove(at: i)
                    }
                }
            }
            
            
        }
    }
}

对外接口

extension GiftContainerView {
    func showGiftModel(_ giftModel : GiftModel){
        
        //1 判断正在ChannelView和赠送的新礼物的名称是否相同 (userName / giftName)
        if let channelView = checkUsingChannelView(giftModel) {
             channelView.addOnceToCache()   //缓存加一
            return
        }
        //2判断有没有闲置的ChannelView ]
        if let channelView = chackIdleChannelView() {
            channelView.giftModel = giftModel   //设置Model
            return
        }
        
        // 将数据放到缓存中
        cacheGiftModels.append(giftModel)
    }
    
    private func checkUsingChannelView(_ giftModel : GiftModel) -> GiftChannelView?{
        for channelView in channelViews{
            if giftModel.isEqual(channelView.giftModel) && channelView.state != .endAnimating{
                return channelView
            }
        }
        return nil
    }
    
    private func chackIdleChannelView() -> GiftChannelView?{
        for channelView in channelViews {
            if channelView.state == .idle {
                return channelView
            }
        }
        return nil
    }
    
}

Github https://github.com/BRburen/-.git

相关文章

  • 礼物通道

    直播礼物动画 1礼物展示的View 礼物展示View上需要!通道 创建所需要的View GiftContainer...

  • 礼物通道分流方案

  • 残缺--上帝含蓄的礼物

    残缺蕴含动能,无论是作品还是人,是和外部系统交换的缺口与通道。 是上帝含蓄的礼物。

  • 通道的运用

    复合通道,颜色通道,专色通道,记录选区阿尔法通道,

  • 通道

    channel通道 关闭通道和通道上范围循环 缓冲通道 定向通道 time包中的通道相关函数 select语句 C...

  • 爱的分享

    孩子的问题,并非都是父母的问题。 但孩子的每个问题,都是父母带领孩子发现成长秘籍的礼物通道。 有觉知的父母,在孩子...

  • 梦通道,行通道

    09年的诗呢 那时还真有心情 哪怕现在晃荡如我 也是再也没有当时的心情呢 当时那文艺的 文艺女青年是个贬义词,现在...

  • <>

    通道的高级玩法 单向通道 单向通道是只允许写或者读的通道,定义方式如下: 通道的读写 for语句读写 select...

  • 知识人脉积累好,管理也可转专业-171-90-34-1473

    【实操技巧:双通道职业发展通道中,管理怎么转专业? 我们公司有个职业双通道路径,管理通道与专业通道是...

  • Photoshop百种技巧六

    81. 使用通道处理图片中的天空 A: 复制蓝色通道 去通道工具窗口拖动蓝色通道到创建新通道的按钮上,复制它。点击...

网友评论

      本文标题:礼物通道

      本文链接:https://www.haomeiwen.com/subject/actrbxtx.html