你好,歡迎來到IOS教程網

 Ios教程網 >> IOS編程開發 >> IOS開發基礎 >> iOS 基於 IM 實現仿映客刷禮物連擊效果

iOS 基於 IM 實現仿映客刷禮物連擊效果

編輯:IOS開發基礎

屏幕快照 2016-07-30 上午11.00.51.png

這裡實現了以下功能:

  1. 隨著收到 IM 禮物消息,實時累加禮物數量

  2. 如果超出連擊時間,比如 3s ,則重新開始計數,從 1 開始

  3. 如果在連擊時間內,則在原先基礎上累加

下面把改造思路跟大家分享下:

問題一:之前動畫已經把禮物數目寫死,如何轉化為 IM 實時更新禮物數量
解決辦法 :

這裡引入了一個動畫管理類 AnimOperationManager ,增加了操作緩存池和禮物緩存池,他們都用用戶聊天消息的唯一標識 userID 作為 key,這裡參考了 SDWebImage 用 URL 做為下載操作的唯一標識。

/// 操作緩存池@property (nonatomic,strong) NSCache *operationCache;/// 禮物緩存池@property (nonatomic,strong) NSCache *userGigtInfos;


把收到的每一條 IM 禮物消息看作是一個動畫操作,這樣就形成了一個禮物隊列,後面的邏輯是,在收到 IM 禮物消息時:

禮物緩存池裡有用戶禮物信息

  • 如果操作緩存池沒有動畫操作,創建操作,從上次禮物數量開始累加

  • 如果操作緩存池有動畫操作,直接從上次禮物數量開始累加

禮物緩存池裡沒有用戶禮物信息

  • 如果操作緩存池沒有動畫操作,創建操作,從 1 開始累加

  • 如果操作緩存池有動畫操作,直接從上次禮物數量開始累加

/// 動畫操作 : 需要UserID和回調- (void)animWithUserID:(NSString *)userID model:(GiftModel *)model finishedBlock:(void(^)(BOOL result))finishedBlock {    // 在有用戶禮物信息時
    if ([self.userGigtInfos objectForKey:userID]) {        // 如果有操作緩存,則直接累加,不需要重新創建op
        if ([self.operationCache objectForKey:userID]!=nil) {
            AnimOperation *op = [self.operationCache objectForKey:userID];
            op.presentView.giftCount = model.giftCount;
            [op.presentView shakeNumberLabel];            return;
        }         // 沒有操作緩存,創建op
        AnimOperation *op = [AnimOperation animOperationWithUserID:userID model:model finishedBlock:^(BOOL result,NSInteger finishCount) {            // 回調
            if (finishedBlock) {
                finishedBlock(result);
            }            // 將禮物信息數量存起來
            [self.userGigtInfos setObject:@(finishCount) forKey:userID];            // 動畫完成之後,要移除動畫對應的操作
            [self.operationCache removeObjectForKey:userID];            // 延時刪除用戶禮物信息
            dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
                [self.userGigtInfos removeObjectForKey:userID];
            });

        }];        // 注意:下面兩句代碼是和無用戶禮物信息時不同的,其余的邏輯一樣
        op.presentView.animCount = [[self.userGigtInfos objectForKey:userID] integerValue];
        op.model.giftCount = op.presentView.animCount + 1;

        op.listView = self.parentView;
        op.index = [userID integerValue] % 2;        // 將操作添加到緩存池
        [self.operationCache setObject:op forKey:userID];        // 根據用戶ID 控制顯示的位置
        if ([userID integerValue] % 2) {            if (op.model.giftCount != 0) {
                op.presentView.frame  = CGRectMake(-self.parentView.frame.size.width / 2, 300, self.parentView.frame.size.width / 2, 40);
                op.presentView.originFrame = op.presentView.frame;
                [self.queue1 addOperation:op];
            }
        }else {            if (op.model.giftCount != 0) {
                op.presentView.frame  = CGRectMake(-self.parentView.frame.size.width / 2, 240, self.parentView.frame.size.width / 2, 40);
                op.presentView.originFrame = op.presentView.frame;
                [self.queue2 addOperation:op];
            }
        }
    }    // 在沒有用戶禮物信息時
    else
    {   // 如果有操作緩存,則直接累加,不需要重新創建op
        if ([self.operationCache objectForKey:userID]!=nil) {
            AnimOperation *op = [self.operationCache objectForKey:userID];
            op.presentView.giftCount = model.giftCount;
            [op.presentView shakeNumberLabel];            return;
        }

        AnimOperation *op = [AnimOperation animOperationWithUserID:userID model:model finishedBlock:^(BOOL result,NSInteger finishCount) {            // 回調
            if (finishedBlock) {
                finishedBlock(result);
            }            // 將禮物信息數量存起來
            [self.userGigtInfos setObject:@(finishCount) forKey:userID];            // 動畫完成之後,要移除動畫對應的操作
            [self.operationCache removeObjectForKey:userID];            // 延時刪除用戶禮物信息
            dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
                [self.userGigtInfos removeObjectForKey:userID];
            });

        }];
        op.listView = self.parentView;
        op.index = [userID integerValue] % 2;        // 將操作添加到緩存池
        [self.operationCache setObject:op forKey:userID];        if ([userID integerValue] % 2) {            if (op.model.giftCount != 0) {
                op.presentView.frame  = CGRectMake(-self.parentView.frame.size.width / 2, 300, self.parentView.frame.size.width / 2, 40);
                op.presentView.originFrame = op.presentView.frame;
                [self.queue1 addOperation:op];
            }
        }else {            if (op.model.giftCount != 0) {
                op.presentView.frame  = CGRectMake(-self.parentView.frame.size.width / 2, 240, self.parentView.frame.size.width / 2, 40);
                op.presentView.originFrame = op.presentView.frame;
                [self.queue2 addOperation:op];
            }
        }

    }

}

禮物信息維持 3s,3s 內不連擊送禮物,禮物信息刪除,從1開始計數;這裡大家可以根據項目調整

// 3s不連擊刪除用戶禮物信息  這裡可以根據需求自己設定dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        [self.userGigtInfos removeObjectForKey:userID];
});
問題二:由於動畫設計時並沒有明確分段,不能實時收到 IM 消息後累加
解決辦法 :

這裡特別感謝 @小蝸牛同學 的幫助,不然動畫流程還需要重新設計下。這裡把動畫拆分成了三段,視圖顯示-累加動畫-視圖消失;在累加動畫中,增加了以下代碼:

[NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(hidePresendView) object:nil];//可以取消成功。
 [self performSelector:@selector(hidePresendView) withObject:nil afterDelay:2];

這樣在連續收到 IM 消息時,可以把之前視圖消失的動畫執行取消掉,只執行最後收到 IM 禮物消息後,執行視圖消失的動畫。

以上便是此次完善的思路,同學們可以根據自己項目進行改造,如果發現什麼 bug 或者好的思路,歡迎大家一起討論交流~祝好。

PS:此次更新比較大,so,發文說明下。今後如果同學們對這個動畫感興趣,可以關注 github 更新。

Demo 地址:
https://github.com/cooxu/PresentAnimView.git

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