你好,歡迎來到IOS教程網

 Ios教程網 >> IOS編程開發 >> IOS開發基礎 >> 仿映客刷禮物效果 代碼優化

仿映客刷禮物效果 代碼優化

編輯:IOS開發基礎

上一篇文章《仿映客刷禮物效果---基本邏輯實現》中,分析了刷禮物效果的基本流程與具體實現代碼。但還有一些BUG和一些可優化的地方沒有處理,現在我們就來分析下這些遺留的問題。當然個人的能力是有限的,肯定還有很多我沒有發現到的問題,如果大家在使用過程中有遇到其它的問題,歡迎大家及時指出,我好及時完善。

優化後的效果圖如下:

1344789-64b562bafc7043f9.png

效果圖.png


廢話不多說,先看問題。

問題一

問題描述

問題效果圖如下圖:

1344789-cbaceabf470ded87.gif

問題一.gif


從圖中可以看到:當一個禮物動畫組正在執行隱藏動畫時,這時恰好收到一個新的與之相同類型的禮物消息,按正常邏輯來看,這個新的禮物消息應該應該作為一個新的動畫組開始展示。但是,從GIF圖中可以看到,連送按鈕再次出現的時,新的動畫組並沒有開始展示,那新接收到禮物消息去哪裡了呢?

問題原因

如果將隱藏動畫的動畫時間設置長一點,重復上面的問題流程。你就會發現,其實新接收到的禮物消息並不是消失了,而是被判定為一次連乘動畫。所以這時其實是一邊執行隱藏動畫,一遍執行連乘動畫,這就導致連乘動畫很難被看到,從而造成了新接收到的禮物消息消失了。

問題解決

知道了問題原因,解決問題就非常簡單了。這裡我的解決方法是:讓cell在執行隱藏動畫時不被判定為正在執行動畫,因此我給cell設置了幾種動畫狀態,其邏輯關系如下圖所示:

1344789-8098e88b3f2bc928.png

動畫狀態邏輯.png


有了動畫狀態之後,只用修改動畫檢測的判斷條件就可以了,修改後的代碼如下:

- (PresentViewCell *)examinePresentingCell:(id)obj
{
    for (PresentViewCell *cell in self.showCells) {
        if ([cell.sender isEqualToString:[obj sender]] && [cell.giftName isEqualToString:[obj giftName]]) {
            //當前正在展示動畫並且不是隱藏動畫
            if (cell.state != AnimationStateNone && cell.state != AnimationStateHiding) return cell;
        }
    }
    return nil;
}

如果當前沒有不為空閒並且也沒有在隱藏動畫,就判定當前cell可以執行連乘動畫。
運行程序,再次測試,就會發現當cell正在執行隱藏動畫時收到一條相同類型消息,新的消息會在新的動畫組中展示,或是等有了空閒的cell時在展示。(修改後的具體效果可以在Demo中驗證,下同)

問題二

問題描述

問題效果圖如下:

1344789-6b88b15393331eb8.gif

問題一.gif


從圖中可以看到:當連續多次快速的點擊同一個發送按鈕時,連乘的動畫效果就消失了。

問題原因

很明顯這裡的問題原因就是因為:上一次點擊的連乘動畫還沒執行完,就開始了下一次連乘動畫,從而造成了這種效果。

問題解決

從問題原因中很容易想到這裡需要用到緩存機制,即等到上一次動畫執行完了再執行下一次動畫。首先我們很容易想到的就是NSOperationQueue和dispatch_group_t,這是系統封裝的兩個任務隊列,很容易實現上面的需求,而且還特別簡單,只用在shakeAnimationWithNumber:裡面實現緩存機制就行了。這裡介紹下dispatch_group_t隊列的實現方法,其代碼如下:

- (void)shakeAnimationWithNumber:(NSInteger)number
{
    if (!_queue && !_group) {
        _queue = dispatch_queue_create("com.shakeCache.queue", DISPATCH_QUEUE_SERIAL);
        _group = dispatch_group_create();
        dispatch_group_notify(_group, dispatch_get_main_queue(), ^{
            dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
                [self hiddenAnimationOfShowShake:YES];
            });
        });
    }
    dispatch_group_async(_group, _queue, ^{
        [self startShakeAnimationWithNumber:number completion:nil];
    });
}

代碼很簡單,就是創建一個全局的串行隊列,如果group任務完成就延時執行隱藏動畫,每次調用都想group中添加一個連乘動畫任務。
運行程序,你會發現問題還是存在,這是為什麼呢?其實原因很簡單,就是因為:UIView封裝的動畫是在子線程中執行,與添加任務操作不在同一個線程中。所以雖然任務是順序添加的,但動畫的執行並不是串行執行的。
這裡的解決辦法是:自己實現緩存--收到連乘動畫先緩存,如果有緩存並且沒有正在執行連乘動畫,就取緩存,開始動畫,動畫完成就刪除緩存,再去取緩存,只到沒有緩存為止。具體實現代碼如下:

- (void)shakeAnimationWithNumber:(NSInteger)number
{
    if (number > 0) [self.caches addObject:@(number)];
    if (self.caches.count > 0 && _state != AnimationStateShaking) {
        NSInteger cache        = [self.caches.firstObject integerValue];
        [self.caches removeObjectAtIndex:0];//不能刪除對象,因為可能有相同的對象
        __weak typeof(self) ws = self;
        [self startShakeAnimationWithNumber:cache completion:^(BOOL finished) {
            [ws shakeAnimationWithNumber:-1];//傳-1是為了緩存不被重復添加
        }];
    }
}

再次運行程序,就會發現連乘動畫是串行執行了。

問題三

問題描述

在開始下一次動畫去緩存時,這時剛好收到一個與取出的緩存相同類型的消息,又會去取緩存。在極端的情況下,這會造成兩個相同類型的禮物動畫同時展示。
因為這是一個邏輯上特別極端的情況,所以這裡沒有給出效果圖。

問題原因

這個問題原因其實就是因為:取緩存到動畫開始這段時間內收到一條與取出緩存相同類型的消息,導致這個新的消息在做動畫檢測時沒有檢測出來,所以新的消息可能也會作為新的動畫組開始展示。

問題解決

這裡的解決辦法是將取緩存到動畫開始這個時間縮減到最短,也就是在開始展示動畫前就將cell的動畫狀態從AnimationStateNone設置成AnimationStateShowing。
關於這個問題,有興趣的可以自行測試,測試時記得要增大取緩存到開始動畫這段時間。具體操作就是:增大cell的顯示動畫時間,並且等cell的顯示動畫完成再將cell的動畫狀態從AnimationStateNone設置成AnimationStateShowing。(如果有測試出問題的,記得將問題效果的gif圖分享給我!拜謝了!)

問題四

解決一個問題,就會帶來新的問題。這裡給動畫做了這麼多的緩存之後帶來的新的問題是什麼呢!想必測試過的應該已經發現了:連送按鈕已經隱藏了,但是連乘動畫還在執行,這肯定是不合邏輯的。

對於這個問題,只有在項目中有要求出現連送按鈕才會出現,而且出現了也不一定算是問題(映客也沒解決這個問題),所以這裡就不解決這個問題了,如果確實有要求的,這裡提供下思路:因為展示動畫和連乘動畫的動畫時間都是確定的,所以很容易計算出執行完當前動畫組需要的時間。然後每接收到一個連乘動畫就對這個時間進行更新,並用代理或其它的形式將這個時間值傳遞出去,最後根據這個值對連送按鈕進行控制就可以了。(當然了,有實現了這個思路或是有更好思路的,方便的話,也請分享給我,再次拜謝了!)

一個好的功能應該除了具有易用性之外,還應該具有良好的擴展性。

擴展

因為項目的需求不同,所以對展示動畫與隱藏動畫的要求也各部相同。這裡就提供了對這連個動畫自定義的接口,接口名如下:

/**
 *  自定義展示動畫
 *
 *  @param flag 是否帶有連乘動畫
 */- (void)customDisplayAnimationOfShowShakeAnimation:(BOOL)flag;/**
 *  自定義隱藏動畫
 *
 *  @param flag 是否帶有連乘動畫
 */- (void)customHideAnimationOfShowShakeAnimation:(BOOL)flag;

如果想對這兩動畫進行簡單的自定義,就可以在自定義cell中重寫這兩方法。需要注意的是,這兩方法是在UIView封裝的動畫的animations回調中調用,所以只用修改cell的frame就夠了。

一般項目中通過這種方法自定義cell的展示和隱藏動畫就可以滿足需求,如果項目中確實需要更絢麗的動畫效果,就需要修改PrentViewCell的showAnimationWithModel:showShakeAnimation:prepare:completion:方法和hiddenAnimationOfShowShake:方法中的動畫代碼。

當然,還有其它的地方可以擴展,這裡就不一一對其封裝了。優化後的Demo下載地址

最後,還是開篇那句話:個人的能力有限,肯定還有很多我沒有發現到的問題,如果大家在使用過程中有遇到其它的問題,歡迎大家及時指出,我好及時完善。



文章轉自 Rasping的簡書
  1. 上一頁:
  2. 下一頁:
蘋果刷機越獄教程| IOS教程問題解答| IOS技巧綜合| IOS7技巧| IOS8教程
Copyright © Ios教程網 All Rights Reserved