最近在研究直播的相關(guān)知識(shí)人断,在網(wǎng)上看到了不少優(yōu)秀的開(kāi)源項(xiàng)目蜗侈,可惜都沒(méi)有看到映客那個(gè)刷禮物的效果,于是手癢癢搬瑰,決定自己做一個(gè)~
首先從簡(jiǎn)單的開(kāi)始付呕,文字描邊+連擊效果,這個(gè)比較簡(jiǎn)單跌捆,只要重寫(xiě) UILabel 的
- (void)drawTextInRect:(CGRect)rect
就可以達(dá)到文字描邊的效果徽职;然后開(kāi)定時(shí)器,讓數(shù)字增加佩厚,動(dòng)畫(huà)效果用關(guān)鍵幀動(dòng)畫(huà)控制姆钉。然后仿照映客的 UI 自定義 View ,控制動(dòng)畫(huà),從屏幕外面進(jìn)入潮瓶,然后顯示連擊效果陶冷,最后隱藏,恢復(fù)到初始位置毯辅。
上面的動(dòng)畫(huà)效果只要稍微有點(diǎn)動(dòng)畫(huà)基礎(chǔ)埂伦,很容易就搞定了。做到這里我冷靜下來(lái)思恐,不再往下面做了沾谜,因?yàn)槭虑檫h(yuǎn)遠(yuǎn)沒(méi)有想象的那么簡(jiǎn)單。首先考慮的是胀莹,在收到禮物消息的回調(diào)時(shí)去賦值數(shù)據(jù)源基跑, 運(yùn)行動(dòng)畫(huà),但是這個(gè)回調(diào)是是一個(gè)字典數(shù)組描焰,里面包含了一段時(shí)間內(nèi)多條消息媳否,他們是有順序的,這是其一荆秦;其二篱竭,這個(gè)回調(diào)調(diào)用次數(shù)會(huì)很頻繁,短時(shí)間內(nèi)就會(huì)收到更多的消息數(shù)組步绸。所以需要把這些消息處理成隊(duì)列室抽,然后播放動(dòng)畫(huà)效果,一個(gè)動(dòng)畫(huà)效果播放完成后靡努,再?gòu)南㈥?duì)列中取下一個(gè)消息坪圾,繼續(xù)播放下一個(gè)動(dòng)畫(huà),這樣才能保證動(dòng)畫(huà)的播放順序不回亂惑朦。
說(shuō)到隊(duì)列的話(huà)就想到了多線(xiàn)程兽泄,NSOperation ,我們可以重寫(xiě)它漾月,然后在 start 方法中添加動(dòng)畫(huà)病梢,但是注意我們只是需要讓這些消息排隊(duì),更新 UI 還是要在主線(xiàn)程操作梁肿;我們還要手動(dòng)觸發(fā) NSOperation 的 KVO蜓陌,告訴這個(gè)操作什么時(shí)候開(kāi)始,什么時(shí)候算是結(jié)束吩蔑,我們想在一個(gè)動(dòng)畫(huà)播放完畢后再執(zhí)行下一個(gè)動(dòng)畫(huà)钮热,于是我這里定義了一個(gè) block ,在動(dòng)畫(huà)結(jié)束時(shí)烛芬,傳遞給 NSOperation 隧期,告訴它動(dòng)畫(huà)結(jié)束了飒责。
@synthesize finished = _finished;
@synthesize executing = _executing;
- (instancetype)init
{
self = [super init];
if (self) {
_executing = NO;
_finished = NO;
}
return self;
}
- (void)start {
if ([self isCancelled]) {
self.finished = YES;
return;
}
self.executing = YES;
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
_presentView = [[PresentView alloc] init];
_presentView.model = _model;
// i % 2 控制最多允許出現(xiàn)幾行
_presentView.frame = CGRectMake(-self.listView.frame.size.width / 2, 300 - (_index % 2) * 70, self.listView.frame.size.width / 2, 40);
_presentView.originFrame = _presentView.frame;
[self.listView addSubview:_presentView];
[self.presentView animateWithCompleteBlock:^(BOOL finished) {
self.finished = finished;
}];
}];
}
#pragma mark - 手動(dòng)觸發(fā) KVO
- (void)setExecuting:(BOOL)executing
{
[self willChangeValueForKey:@"isExecuting"];
_executing = executing;
[self didChangeValueForKey:@"isExecuting"];
}
- (void)setFinished:(BOOL)finished
{
[self willChangeValueForKey:@"isFinished"];
_finished = finished;
[self didChangeValueForKey:@"isFinished"];
}
注意這里 :
_presentView.frame = CGRectMake(-self.listView.frame.size.width / 2, 300 - (_index % 2) * 70, self.listView.frame.size.width / 2, 40);// i % 2 控制最多允許出現(xiàn)幾行
queue.maxConcurrentOperationCount = 2; // 隊(duì)列分發(fā)
當(dāng)時(shí)其實(shí)只是實(shí)現(xiàn)了一個(gè)隊(duì)列,按順序一個(gè)一個(gè)播放仆潮,如何實(shí)現(xiàn) N 列并發(fā)呢宏蛉?其實(shí)把這些并發(fā)的動(dòng)畫(huà)隊(duì)列想象成圖片的多并發(fā)異步下載就好了,下意識(shí)地就加了上面兩句控制并發(fā)列數(shù)的代碼性置。能這么順利做出來(lái)拾并,是因?yàn)樽罱屑?xì)研究了 SDWebImage 的源碼,不覺(jué)得重寫(xiě) NSOperation 那個(gè)方式很熟悉么~哈哈鹏浅。最近工作忙嗅义,動(dòng)畫(huà)的細(xì)節(jié)和封裝性沒(méi)有再完善,不過(guò)易用性我感覺(jué)還是很好的篡石,最后附上 demo 地址和使用方法,祝大家玩得開(kāi)心~
更新1:解決視圖重疊問(wèn)題
Demo 地址:https://github.com/cooxu/PresentAnimView.git
問(wèn)題交流:icooxu@163.com