禮物連擊動(dòng)畫
基礎(chǔ)知識
digitalLable:1.畫文字 ?2.lable動(dòng)畫回調(diào)
channelView:0.幾種狀態(tài) 1.當(dāng)執(zhí)行完(lable動(dòng)畫回調(diào))--檢測是否有緩存數(shù)量-有就遞歸執(zhí)行-count==0 ? 2.單模型緩存--數(shù)量? 3.動(dòng)畫 ?chanel回調(diào) 4.提供對外函數(shù)--增加正在執(zhí)行動(dòng)畫的數(shù)量---number
containnerView:0.當(dāng)執(zhí)行chanel回調(diào)-檢測多模型緩存--數(shù)量和類型--如果有就賦值數(shù)量和第一個(gè)模型--執(zhí)行動(dòng)畫 ?1.提供對外插入模型方法:1.1檢測是否和正在執(zhí)行的相同--如果有增加chinel緩存數(shù)量--沒有執(zhí)行1.2 ? 1.2檢測是否有空通道有就直接賦值執(zhí)行動(dòng)畫---沒有執(zhí)行1.3 ?1.3前兩部沒有加入到 模型緩存中
try處理
return try! userInfo.build()
userInfo.build()返回值中有throw? 需要進(jìn)行 try!處理
0.層級 關(guān)系 view? containView? channelView digitalview HYGiftModel
view: 只傳入model就可以
containView: 1.判斷是否有閑置通道 ?2.是否禮物模型相同 3.單通道的緩存數(shù)量
channelView: 對單個(gè)禮物的狀態(tài) ?和 緩存數(shù)量的執(zhí)行 和 給模型賦值后執(zhí)行動(dòng)畫
HYGiftModel: 判斷禮物是否相同(重寫isEqual 根據(jù)giftname 和發(fā)送者name )
1.HYDigitLabel ?
1.0畫出數(shù)字text ? 1.1設(shè)置開始動(dòng)畫方法----結(jié)束并且有回調(diào)
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.校驗(yàn)?zāi)P褪欠裼兄?/p>
guard let giftModel = giftModel else {
return
}
// 2.將giftModel中屬性設(shè)置到控件中
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 ?正在執(zhí)行
case endWating 等待結(jié)束
case ending 結(jié)束
}
2.1
fileprivate func performShowAnimating() {
狀態(tài)改變
state = .animating
UIView.animate(withDuration: 0.25, animations: {
self.frame.origin.x = 0
self.alpha = 1.0
}) { (_) in
橫條停到位置后----開始執(zhí)行數(shù)字彈跳動(dòng)畫
self.performDigitAnimating()
}}
數(shù)字彈跳動(dòng)畫
fileprivate func performDigitAnimating() {
// 1.將digitLabel的alpha值設(shè)置為1
digitLabel.alpha = 1
// 2.設(shè)置digitLabel上面顯示的數(shù)字
currentNumber += 1
digitLabel.text = " x\(currentNumber)"
// 3.執(zhí)行動(dòng)畫
digitLabel.startScaleAnimating {
if self.cacheNumber > 0 {
self.cacheNumber -= 1
self.performDigitAnimating()
相當(dāng)于遞歸執(zhí)行 直到self.cacheNumber = 0
} else {
如果沒有self.cacheNumber 狀態(tài)就改變
self.state = .endWating
等待執(zhí)行結(jié)束動(dòng)畫
self.perform(#selector(self.performEndAnimating), with: nil, afterDelay: 3.0)
}
}
@objc fileprivate func performEndAnimating() {
狀態(tài)改變--正在結(jié)束 ?往右走的過程
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
結(jié)束完成通知控制器,看是否還有任務(wù)需要執(zhí)行
self.finishedCallback?(self)
}
}
// MARK:- 對外提供的函數(shù)---對單一通道的處理
extension HYGiftChannelView {
func addOnceToCache() {
若果正在等待結(jié)束----讓其取消等待--立即執(zhí)行-改變狀態(tài)
if state == .endWating {
NSObject.cancelPreviousPerformRequests(withTarget: self)
self.state = .animating
performDigitAnimating()
} else {
其他情況就讓其緩存+1
cacheNumber += 1
}
}
}
對containView處理
extension HYGiftContainerView {
fileprivate func setupUI() {
// 1.根據(jù)當(dāng)前的渠道數(shù),創(chuàng)建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.檢查緩存中是否有內(nèi)容
guard self.cacheGiftModels.count != 0 else {
return
}
// 2.取出模型
let firstGiftModel = self.cacheGiftModels.first!
self.cacheGiftModels.removeFirst()
// 3.取出和giftModel相同模型的個(gè)數(shù)
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執(zhí)行緩存中禮物模型的動(dòng)畫
channelView.cacheNumber = cacheNumber
channelView.giftModel = firstGiftModel
}
}
}
}
對外提供的函數(shù)--如何調(diào)用
extension HYGiftContainerView {
func insertGiftModel(_ giftModel : HYGiftModel) {
// 1.判斷是否有正在執(zhí)行動(dòng)畫的渠道的模型和新插入的模型一致
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.判斷傳入的內(nèi)容是否有值
guard let object = object as? HYGiftModel else {
return false
}
// 2.判斷贈(zèng)送者和贈(zèng)送的禮物名稱是否相同
return object.senderName == senderName && object.giftName == giftName
}
}