天天看點

【如何快速的開發一個完整的iOS直播app】(禮物篇)

搭建禮物清單

使用modal,設定modal樣式為custom,就能做到從小往上顯示禮物清單,并且能看見前面的直播界面

禮物模型設計

一開始建立3個禮物模型,儲存到數組,傳入給禮物View展示,本來禮物資料應該從伺服器擷取,這裡沒做了。

到時候拿到禮物View就能拿到對應按鈕,傳給伺服器就好了.

禮物模型設計

禮物模型

使用者模型(userID,userName),用于标志哪個使用者發送,這裡為友善測試,保證UserID一樣

禮物ID(giftID),用于标志目前禮物

禮物名稱(giftName)

禮物總數(giftCount),用于記錄禮物連發數,總共發了多少禮物

發送禮物的房間Key(roomKey),用于知道是發送個哪個房間

@interfaceXMGGiftItem:NSObject

// 禮物ID

@property(nonatomic,assign)NSInteger giftId;

// 使用者模型:記錄哪個使用者發送

@property(nonatomic,strong) XMGUserItem *user;// 禮物名稱

@property(nonatomic,strong) XMGUserItem *giftName;// 禮物個數,用來記錄禮物的連擊數

@property(nonatomic,assign)NSIntegergiftCount;// 發送哪個房間@property(nonatomic,strong)NSString*roomKey;

+ (instancetype)giftWithGiftId:(NSInteger)giftId userId:(NSInteger)userId giftCount:(NSInteger)giftCount roomKey:(NSString*)roomKey;

@end+ (instancetype)giftWithGiftId:(NSInteger)giftId giftCount:(NSInteger)giftCount roomKey:(NSString*)roomKey giftName:(NSString*)giftName{  

  XMGGiftItem *item = [[selfalloc] init];    

item.giftId = giftId;  

  item.user = [[XMGUserItem alloc] init];// ID一樣,模拟隻有一個使用者item.user.id =1;   

 item.user.userName [email protected]"使用者1";  

  item.giftCount = giftCount;   

 item.roomKey = roomKey;   

 item.giftName = giftName;returnitem;

}

監聽禮物點選

點選禮物的時候,發送禮物

這裡使用了websocket搭建的背景伺服器,進行禮物發送

// 發送禮物

SocketIOClient *socket = [SocketIOClient shareSocketIOClient];  

  XMGGiftItem *gift = [XMGGiftItemgiftWithGiftId:sender.taguserId:socket.user.idgiftCount:1roomKey:socket.roomKey];    [socketemit:@"gift"with:@[gift.mj_keyValues]];

三、禮物界面監聽禮物發送

// 監聽禮物

SocketIOClient *socket = [SocketIOClient shareSocketIOClient];    

[socketon:@"gift"callback:^(NSArray * _Nonnull data, SocketAckEmitter * _Nonnull ask) {  

      NSLog(@"接收到禮物%@",data);     

   XMGGiftItem *item = [XMGGiftItemmj_objectWithKeyValues:data[0]];

// 顯示禮物動畫

[selfsetupGiftAnim:item];  

  }];

四、設定禮物動畫

顯示禮物業務邏輯

1.并不是每次接收到禮物,都需要建立對應禮物動畫View,一次最多顯示2個禮物View,當執行完一個禮物,就判斷是否還有未執行的禮物,繼續執行.

2.需要搞個禮物隊列(數組)儲存所有需要執行的禮物模型,并不是隻儲存未執行的禮物模型.

2.1什麼是需要執行的禮物模型?每一個需要執行的禮物模型都對應一個禮物View

2.2 如果隻儲存未執行的禮物,不記錄之前的執行禮物,沒法判斷下一個禮物是否是連發禮物,因為拿不到之前的做判斷。

2.3 什麼是連發禮物,同一個使用者,連續發送相同的禮物。

2.4 是以每接收一個新的禮物,需要與之前的禮物對比,是否是同一個人發送的相同禮物。

@property(nonatomic,strong)NSMutableArray*giftQueue;

- (NSMutableArray*)giftQueue{

if(_giftQueue ==nil) { 

 _giftQueue = [NSMutableArrayarray];

}

return_giftQueue;

}

3.判斷是否是連發禮物

3.1 周遊禮物隊列中所有禮物,判斷目前接收的禮物與之前禮物是否有相同的UserID和相同的禮物ID。

3.2 如果有相同的UserID和相同的禮物ID,就表示是連發禮物,,把禮物模型的禮物總數+1.

3.3 不需要把連發禮物添加到禮物隊列中,因為隻要是連發禮物就表示之前已經有相同的禮物,會和之前禮物共用同一個禮物View,不需要建立新的禮物View.

3.4 是以隻要是連發禮物,就直接return,不做操作.

```

pragma mark - 判斷目前接收禮物是否屬于連發禮物

(BOOL)isComboGift:(XMGGiftItem)gift

{

XMGGiftItemcomboGift = nil;

for (XMGGiftItem *giftItem in self.giftQueue) {

// 如果是連發禮物就記錄下來if(giftItem.giftId== gift.giftId && giftItem.userId== gift.userId) {comboGift= giftItem;  }

}

if (comboGift) { // 連發禮物有值

// 禮物模型的禮物總數+1comboGift.giftCount +=1;returnYES;

}

return NO;

}

*4.如果不是連發禮物,直接把接收到的禮物添加到禮物隊列  *5.搞個數組記錄目前顯示的動畫View*5.1最多顯示兩個禮物動畫View,記錄目前正在做動畫的View*5.2如果超過2個顯示的View,就先不建立禮物View,直接retun

@property (nonatomic, strong) NSMutableArray *giftAnimViews;

(NSMutableArray *)giftAnimViews

{

if (_giftAnimViews == nil) {

_giftAnimViews = [NSMutableArray array];

}

return _giftAnimViews;

}

```

6.過濾掉以上2個條件之後,處理禮物動畫

6.1 建立禮物View

6.2 設定禮物View的frame

6.2.1 分為上下兩部分,先顯示到底部,在顯示頂部

6.2.2 怎麼才知道目前禮物View顯示在哪部分,搞個位置數組,每次從數組中取出一個位置,取完,就移除,這樣下次就不會顯示重複的地方了。

6.3 添加禮物View到控制器的View中

6.4 做禮物平移動畫

6.5 禮物平移動畫做完,開始做連擊動畫

```

// 處理禮物動畫

(void)handleGiftAnim:(XMGGiftItem)gift

{

// 1.建立禮物動畫的View

XMGGiftAnimViewgiftView = [XMGGiftAnimView giftAnimView];

CGFloat h = self.view.bounds.size.height * 0.5;

CGFloat w = self.view.bounds.size.width;

// 取出禮物位置

id position = self.positions.lastObject;

// 從數組移除位置

[self.positions removeObject:position];

CGFloat y = [position floatValue] * h;

// 2.設定禮物View的frame

giftView.frame = CGRectMake(0, y, w, h);

// 3.傳遞禮物模型

giftView.gift = gift;

// 記錄目前位置

giftView.tag = [position floatValue];

// 添加禮物View

[self.view addSubview:giftView];

// 添加記錄禮物View數組

[self.giftAnimViews addObject:giftView];

__weak typeof(self) weakSelf = self;

giftView.dismissView = ^(XMGGiftAnimView *giftView){

[weakSelf dismissView:giftView];

};

// 設定動畫

giftView.transform = CGAffineTransformMakeTranslation(-w, 0);

[UIView animateWithDuration:.25 delay:0 usingSpringWithDamping:0.6 initialSpringVelocity:1 options:UIViewAnimationOptionCurveLinear animations:^{

giftView.transform = CGAffineTransformIdentity;

} completion:^(BOOL finished) {

// 開始連擊動畫[giftView startComboAnim];

}];

}

*7.禮物連擊動畫      *7.1封裝到禮物View中,禮物需要拿到禮物連擊Label做事情      *7.2每隔一段時間,需要修改連擊數,搞個定時器,每隔0.3秒做事情      *7.3連擊動畫,也需要控制在0.3秒剛好做完,就能直接做下一次動畫。      *7.4搞個屬性記錄目前連擊數,沒執行一次連擊就++,當目前連擊數大于禮物總數的時候,表示連擊動畫執行完畢,需要銷毀定時器,銷毀目前禮物View      *7.5`注意點`:當目前連擊數大于禮物總數的時候,不能馬上确定連擊動畫執行完畢,因為電腦執行速度大于使用者點選速度,有可能使用者在點的時候,沒有電腦執行快,電腦執行完直接把禮物View移除了,就看不到連擊效果了。      *7.6是以需要延遲銷毀定時器,而且隻要有新的連擊數了,需要取消銷毀定時器,要不然可能連擊數還沒顯示完,定時器就銷毀了

(void)startComboAnim{

if (_timer == nil) {

_timer = [NSTimer scheduledTimerWithTimeInterval:0.3 target:self selector:@selector(combo) userInfo:nil repeats:YES];

_curComboCount = 1;

}

}

// 連擊

(void)combo

{

// 目前連發數,已經顯示完畢

if (_curComboCount > _gift.giftCount) { // 停止定時器

// 停止定時器[selfperformSelector:@selector(cancel)withObject:nilafterDelay:1];

} else {

// 修改label顯示_comboView.text = [NSStringstringWithFormat:@"x%ld",_curComboCount];  [UIViewanimateWithDuration:0.15animations:^{      _comboView.transform = CGAffineTransformMakeScale(3,3);  }completion:^(BOOL finished) {    [UIViewanimateWithDuration:0.15animations:^{        _comboView.transform = CGAffineTransformIdentity;    }];  }];// 取消定時器銷毀[NSObjectcancelPreviousPerformRequestsWithTarget:selfselector:@selector(cancel)object:nil];  _curComboCount++;

}

}

```

8.連擊動畫做完,

8.1 需要停止定時器

8.2 需要移除禮物動畫的View

8.3 把禮物動畫的View和禮物都移除數組,需要回到之前控制器,用Block

注意點:cancel方法可能會調用多次,定時器沒有銷毀,就會一直調用cancel方法,但是隻需要執行一次,需要搞個屬性記錄下.

原因:因為要在1秒之後才會調用cancle,那在這一秒内,肯定又會調用定時器方法,而且這時候目前連擊數已經大于禮物總數,就會在1秒内多少執行cancle方法,導緻cancle在1秒内調用多次.

- (void)cancel    {

if(_isCancel ==NO) {     

       _isCancel =YES;          

  [_timer invalidate];           

 _timer =nil;

if(_dismissView) {            

    _dismissView(self);         

   }    

    }

    }    

```*9.連擊動畫結束後執行的DismissBlock.    *9.1做禮物View移除動畫,往上移動,透明度為0*9.2把禮物模型從隊列移除    *9.3把禮物View從顯示的禮物View數組移除    *9.4移除目前View    *9.5恢複位置到位置數組        *9.3.1怎麼知道恢複哪個位置?可以用禮物View的tag記錄目前禮物View的位置        *9.3.2如果目前tag為0,需要插入第0個位置,其他情況使用addObject.    *9.6當一個禮物做完動畫,檢視隊列中是否還有未執行的禮物。    ``` 

  - (void)dismissView:(XMGGiftAnimView *)giftView    {       

 [UIViewanimateWithDuration:0.25animations:^{   

         giftView.alpha =0;          

  giftView.transform =CGAffineTransformMakeTranslation(0,-20);       

 } completion:^(BOOLfinished) {

// 移除目前禮物

[self.giftQueue removeObject:giftView.gift];

// 移除目前動畫的

View[giftView removeFromSuperview];

// 移除禮物動畫View數組

[self.giftAnimViews removeObject:giftView];

// 恢複目前位置if(giftView.tag ==0) 

{

// 插入第0個位置

[self.positions insertObject:@(0) atIndex:0];     

       }else{           

     [self.positions addObject:@(giftView.tag)];      

      }

// 判斷隊列中是否還有未處理的禮物

XMGGiftItem *item = [selffetchNoHandleGiftItemOfQueue];

// 處理禮物動畫

if(item) {          

      [selfhandleGiftAnim:item];     

       }    

    }];  

  }    ```

*10.執行完一個禮物,判斷禮物隊列是否還有未執行的禮物    *10.1周遊禮物隊列中所有禮物,檢視是否有未執行的禮物    *10.2取出的禮物,有可能是目前正在執行的禮物,需要排除掉        *10.2.1周遊目前正在執行的禮物View,檢視取出的禮物是否和它的禮物相同,相同表示目前禮物在執行    *10.3擷取到未執行的禮物,直接處理禮物    ```// 搜尋禮物隊列中未執行的禮物

- (XMGGiftItem *)fetchNoHandleGiftItemOfQueue  

  {

// 取出隊列中的禮物

for(

XMGGiftItem *iteminself.giftQueue)

 {

// 目前禮物模型有可能在執行if(![selfisExcutingGift:item])returnitem;       

 }

returnnil;   

 }// 判斷目前禮物是否正在執行

- (BOOL)isExcutingGift:(XMGGiftItem *)gift   

 {

// 判斷目前模型是否已經在執行,執行就不需要在做動畫

for(XMGGiftAnimView *giftViewinself.giftAnimViews) {

if(giftView.gift == gift)returnYES;        

}

returnNO;   

 }    ```

禮物整體業務邏輯

- (void)setupGiftAnim:(XMGGiftItem *)gift  {

//1.判斷目前接收的禮物是否屬于連發禮物 屬于直接return,不需要在重新建立新的動畫Viewif([selfisComboGift:gift])return;

//2.添加到禮物隊列   

   [self.giftQueueaddObject:gift];

//3.判斷目前顯示多少個禮物動畫

Viewif(self.giftAnimViews.count ==2)

return;

//4.處理禮物動畫 

     [selfhandleGiftAnim:gift]; 

 }