礼物连击动画
基础知识
digitalLable:1.画文字 2.lable动画回调
channelView:0.几种状态 1.当执行完(lable动画回调)--检测是否有缓存数量-有就递归执行-count==0 2.单模型缓存--数量 3.动画 chanel回调 4.提供对外函数--增加正在执行动画的数量---number
containnerView:0.当执行chanel回调-检测多模型缓存--数量和类型--如果有就赋值数量和第一个模型--执行动画 1.提供对外插入模型方法:1.1检测是否和正在执行的相同--如果有增加chinel缓存数量--没有执行1.2 1.2检测是否有空通道有就直接赋值执行动画---没有执行1.3 1.3前两部没有加入到 模型缓存中
try处理
return try! userInfo.build()
userInfo.build()返回值中有throw 需要进行 try!处理
0.层级 关系 view containView channelView digitalview HYGiftModel
view: 只传入model就可以
containView: 1.判断是否有闲置通道 2.是否礼物模型相同 3.单通道的缓存数量
channelView: 对单个礼物的状态 和 缓存数量的执行 和 给模型赋值后执行动画
HYGiftModel: 判断礼物是否相同(重写isEqual 根据giftname 和发送者name )
1.HYDigitLabel
1.0画出数字text 1.1设置开始动画方法----结束并且有回调
func startScaleAnimating(_ complection : (() -> Void)? = nil) {
UIView.animateKeyframes(withDuration: 1, delay: 0, options: [], animations: {
UIView.addKeyframe(withRelativeStartTime: 0, relativeDuration: 0.4, animations: {
self.transform = CGAffineTransform(scaleX: 3.0, y: 3.0)
})
UIView.addKeyframe(withRelativeStartTime: 0.4, relativeDuration: 0.8, animations: {
self.transform = CGAffineTransform(scaleX: 0.7, y: 0.7)
})
UIView.addKeyframe(withRelativeStartTime: 0.8, relativeDuration: 1, animations: {
self.transform = CGAffineTransform.identity
})
}) { (_) in
complection?()
}
}
2.HYGiftChannelView 通道view
class HYGiftChannelView: 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: HYDigitLabel!
// MARK: 定义属性
var finishedCallback : ((HYGiftChannelView) -> Void)?
var state : ChannerlViewState = .idle
var cacheNumber : Int = 0
fileprivate var currentNumber : Int = 0
var giftModel : HYGiftModel? {
didSet {
// 1.校验模型是否有值
guard let giftModel = giftModel else {
return
}
// 2.将giftModel中属性设置到控件中
iconImageView.image = UIImage(named: giftModel.senderIcon)
senderLabel.text = giftModel.senderName
giftDescLabel.text = "送出礼物【\(giftModel.giftName)"
giftImageView.image = UIImage(named: giftModel.giftIcon)
// 3.将channelView展示出来
performShowAnimating()
}
}
}
enum ChannerlViewState {
case idle 闲置
case animating 正在执行
case endWating 等待结束
case ending 结束
}
2.1
fileprivate func performShowAnimating() {
状态改变
state = .animating
UIView.animate(withDuration: 0.25, animations: {
self.frame.origin.x = 0
self.alpha = 1.0
}) { (_) in
横条停到位置后----开始执行数字弹跳动画
self.performDigitAnimating()
}}
数字弹跳动画
fileprivate func performDigitAnimating() {
// 1.将digitLabel的alpha值设置为1
digitLabel.alpha = 1
// 2.设置digitLabel上面显示的数字
currentNumber += 1
digitLabel.text = " x\(currentNumber)"
// 3.执行动画
digitLabel.startScaleAnimating {
if self.cacheNumber > 0 {
self.cacheNumber -= 1
self.performDigitAnimating()
相当于递归执行 直到self.cacheNumber = 0
} else {
如果没有self.cacheNumber 状态就改变
self.state = .endWating
等待执行结束动画
self.perform(#selector(self.performEndAnimating), with: nil, afterDelay: 3.0)
}
}
@objc fileprivate func performEndAnimating() {
状态改变--正在结束 往右走的过程
self.state = .ending
UIView.animate(withDuration: 1, animations: {
self.frame.origin.x = UIScreen.main.bounds.width
}) { (_) in
self.alpha = 0.0
self.state = .idle
self.digitLabel.alpha = 0
self.currentNumber = 0
self.cacheNumber = 0
self.frame.origin.x = -self.frame.width
self.giftModel = nil
结束完成通知控制器,看是否还有任务需要执行
self.finishedCallback?(self)
}
}
// MARK:- 对外提供的函数---对单一通道的处理
extension HYGiftChannelView {
func addOnceToCache() {
若果正在等待结束----让其取消等待--立即执行-改变状态
if state == .endWating {
NSObject.cancelPreviousPerformRequests(withTarget: self)
self.state = .animating
performDigitAnimating()
} else {
其他情况就让其缓存+1
cacheNumber += 1
}
}
}
对containView处理
extension HYGiftContainerView {
fileprivate func setupUI() {
// 1.根据当前的渠道数,创建HYGiftChannelView
let w : CGFloat = frame.width
let h : CGFloat = 40
let x : CGFloat = -w
for i in 0..<2 {
let y : CGFloat = (h + 10) * CGFloat(i)
let channelView = HYGiftChannelView.loadChannelView()
channelView.frame = CGRect(x: x, y: y, width: w, height: h)
channelView.alpha = 0.0
addSubview(channelView)
channelViews.append(channelView)
channelView.finishedCallback = {[unowned self] (channelView) in
// 1.检查缓存中是否有内容
guard self.cacheGiftModels.count != 0 else {
return
}
// 2.取出模型
let firstGiftModel = self.cacheGiftModels.first!
self.cacheGiftModels.removeFirst()
// 3.取出和giftModel相同模型的个数
var cacheNumber = 0
for i in (0..<self.cacheGiftModels.count).reversed() {
if self.cacheGiftModels[i].isEqual(firstGiftModel) {
cacheNumber += 1
self.cacheGiftModels.remove(at: i)
}
}
// 4.让闲置的channelView执行缓存中礼物模型的动画
channelView.cacheNumber = cacheNumber
channelView.giftModel = firstGiftModel
}
}
}
}
对外提供的函数--如何调用
extension HYGiftContainerView {
func insertGiftModel(_ giftModel : HYGiftModel) {
// 1.判断是否有正在执行动画的渠道的模型和新插入的模型一致
if let channelView = checkModelInChannerView(giftModel) {
channelView.addOnceToCache()
return
}
// 2.有没有闲置的channelView可以用于展示的礼物
if let channelView = checkIdleChannelView() {
channelView.giftModel = giftModel
return
}
// 3.将模型添加到缓存中
cacheGiftModels.append(giftModel)
}
fileprivate func checkModelInChannerView(_ newGiftModel : HYGiftModel) -> HYGiftChannelView? {
// return channelViews.filter({ newGiftModel.isEqual($0.giftModel) }).first
for channelView in channelViews {
if newGiftModel.isEqual(channelView.giftModel) && channelView.state != .ending {
return channelView
}
}
return nil
}
fileprivate func checkIdleChannelView() -> HYGiftChannelView? {
// return channelViews.filter({ $0.state == .idle }).first
for channelView in channelViews {
if channelView.state == .idle {
return channelView
}
}
return nil
}
}
模型的处理
class HYGiftModel : NSObject {
var senderName : String = ""
var senderIcon : String = ""
var giftIcon : String = ""
var giftName : String = ""
init(senderName : String, senderIcon : String, giftIcon : String, giftName : String) {
self.senderName = senderName
self.senderIcon = senderIcon
self.giftIcon = giftIcon
self.giftName = giftName
}
override func isEqual(_ object: Any?) -> Bool {
// 1.判断传入的内容是否有值
guard let object = object as? HYGiftModel else {
return false
}
// 2.判断赠送者和赠送的礼物名称是否相同
return object.senderName == senderName && object.giftName == giftName
}
}