【如何快速的开发一个完整的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 =@"用户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]; 

 }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值