1. 程式人生 > >【如何快速的開發一個完整的iOS直播app】(禮物篇)

【如何快速的開發一個完整的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]; 

 }