// // QXSkyPraizeView.m // QXLive // // Created by 启星 on 2025/8/16. // #import "QXSkyPraizeView.h" /// 共有12个礼物 static NSInteger giftMaxCount = 12; /// 最少转2圈 static NSInteger minRoundCount = 2; /// 距离4个的时候放慢 static NSInteger toSlowCount = 4; @interface QXSkyPraizeView() /// 目标下标 @property (nonatomic,assign)NSInteger targetIndex; @property (nonatomic,strong)NSMutableArray* targetArrayIndex; @property (nonatomic,strong)NSMutableArray* finishTargetArrayIndex; /// 当前转动到第几个下标 @property (nonatomic,assign)NSInteger currentIndex; /// 转动了多少次 @property (nonatomic,assign)NSInteger roundCount; /// 延时 @property (nonatomic,assign)double delayTime; /// 22 抽一次 33 抽十次 44 抽 100次 @property (nonatomic,assign)NSInteger startType; @property (nonatomic,strong)QXSkyPraizeSubView *currentGiftView; @property (nonatomic,strong)UIView *bgView; @property (nonatomic,strong)NSMutableArray *allViewsArray; @property (nonatomic,strong)dispatch_source_t fastTimer; @property (nonatomic,strong)dispatch_source_t slowTimer; @end @implementation QXSkyPraizeView - (instancetype)init { self = [super init]; if (self) { self.frame = CGRectMake(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT); [self initSubviews]; } return self; } -(void)initSubviews{ UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(hide)]; tap.delegate = self; [self addGestureRecognizer:tap]; self.backgroundColor = [UIColor colorWithWhite:0.0 alpha:0.3]; self.bgView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, SCREEN_WIDTH, ScaleWidth(520)+kSafeAreaBottom)]; self.bgView.backgroundColor = UIColor.whiteColor; [self.bgView addRoundedCornersWithRadius:16 byRoundingCorners:(UIRectCornerTopLeft|UIRectCornerTopRight)]; [self addSubview:self.bgView]; CGFloat topMargin = 60; CGFloat margin = 16; CGFloat space = 10; CGFloat itemWidth = (SCREEN_WIDTH - margin*2 - space*3) / 4; CGFloat itemHeight = itemWidth/7*8;; for (int i = 0; i < giftMaxCount; i++) { QXSkyPraizeSubView *giftView; if (i < 4) { /// 第一行4个 giftView = [[QXSkyPraizeSubView alloc] initWithFrame:CGRectMake(margin+(itemWidth+space)*i, topMargin, itemWidth, itemHeight)]; giftView.titleLabel.text = [NSString stringWithFormat:@"%d",i]; [self.allViewsArray replaceObjectAtIndex:i withObject:giftView]; }else if (i > 3 && i < 6){ /// 第二行两个 if (i == 4) { giftView = [[QXSkyPraizeSubView alloc] initWithFrame:CGRectMake(margin, topMargin+itemHeight+space, itemWidth, itemHeight)]; giftView.titleLabel.text = [NSString stringWithFormat:@"%d",11]; [self.allViewsArray replaceObjectAtIndex:11 withObject:giftView]; }else{ giftView = [[QXSkyPraizeSubView alloc] initWithFrame:CGRectMake(margin+(itemWidth+space)*3, topMargin+itemHeight+space, itemWidth, itemHeight)]; [self.allViewsArray replaceObjectAtIndex:4 withObject:giftView]; giftView.titleLabel.text = [NSString stringWithFormat:@"%d",4]; } }else if (i > 5 && i < 8){ /// 第三行两个 if (i == 6) { giftView = [[QXSkyPraizeSubView alloc] initWithFrame:CGRectMake(margin, topMargin+(itemHeight+space)*2, itemWidth, itemHeight)]; [self.allViewsArray replaceObjectAtIndex:10 withObject:giftView]; giftView.titleLabel.text = [NSString stringWithFormat:@"%d",10]; }else{ giftView = [[QXSkyPraizeSubView alloc] initWithFrame:CGRectMake(margin+(itemWidth+space)*3, topMargin+(itemHeight+space)*2, itemWidth, itemHeight)]; [self.allViewsArray replaceObjectAtIndex:5 withObject:giftView]; giftView.titleLabel.text = [NSString stringWithFormat:@"%d",5]; } }else{ giftView = [[QXSkyPraizeSubView alloc] initWithFrame:CGRectMake(margin+(itemWidth+space)*(i%4), topMargin+(itemHeight+space)*3, itemWidth, itemHeight)]; [self.allViewsArray replaceObjectAtIndex:11-(i-6) withObject:giftView]; giftView.titleLabel.text = [NSString stringWithFormat:@"%d",11-(i-6)]; } [self.bgView addSubview:giftView]; } [self resetViews]; UIButton *btn = [[UIButton alloc] initWithFrame:CGRectMake(16, 20, 100, 40)]; [btn setTitle:@"抽1次" forState:(UIControlStateNormal)]; [btn setTitleColor:UIColor.blueColor forState:(UIControlStateNormal)]; btn.tag = 22; [btn addTarget:self action:@selector(startAction:) forControlEvents:(UIControlEventTouchUpInside)]; [self.bgView addSubview:btn]; UIButton *tenBtn = [[UIButton alloc] initWithFrame:CGRectMake(116, 20, 100, 40)]; [tenBtn setTitle:@"抽10次" forState:(UIControlStateNormal)]; tenBtn.tag = 33; [tenBtn setTitleColor:UIColor.blueColor forState:(UIControlStateNormal)]; [tenBtn addTarget:self action:@selector(startAction:) forControlEvents:(UIControlEventTouchUpInside)]; [self.bgView addSubview:tenBtn]; UIButton *hundredBtn = [[UIButton alloc] initWithFrame:CGRectMake(216, 20, 100, 40)]; [hundredBtn setTitle:@"抽100次" forState:(UIControlStateNormal)]; hundredBtn.tag = 44; [hundredBtn setTitleColor:UIColor.blueColor forState:(UIControlStateNormal)]; [hundredBtn addTarget:self action:@selector(startAction:) forControlEvents:(UIControlEventTouchUpInside)]; [self.bgView addSubview:hundredBtn]; } -(BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch{ return touch.view == self; } -(void)startAction:(UIButton*)sender{ self.startType = sender.tag; /// 获取目标礼物 [self resetViews]; [self getTargetGift]; [self startFastAnimate]; } -(void)resetViews{ self.targetIndex = -1; self.currentIndex = -1; self.roundCount = 0; self.delayTime = 0.3; [self.targetArrayIndex removeAllObjects]; [self.finishTargetArrayIndex removeAllObjects]; if (self.currentGiftView != nil) { self.currentGiftView.isSelected = NO; [self.currentGiftView stopPulseAnimationWithLayer]; } for (QXSkyPraizeSubView *giftView in self.allViewsArray) { giftView.isSelected = NO; [giftView stopPulseAnimationWithLayer]; } } -(void)startFastAnimate{ self.currentGiftView = self.allViewsArray.firstObject; self.currentGiftView.isSelected = YES; [self stopFastAnimate]; if (_fastTimer == nil) { _fastTimer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)); } // dispatch_source_set_timer(_fastTimer, // dispatch_time(DISPATCH_TIME_NOW, 0), // NSEC_PER_SEC * 0.06, // 间隔0.1秒 // NSEC_PER_SEC * 0.01); // 允许误差0.01秒 dispatch_source_set_timer(_fastTimer, dispatch_time(DISPATCH_TIME_NOW, 0.06 * NSEC_PER_SEC), DISPATCH_TIME_FOREVER, // 使用一次性模式 0.01 * NSEC_PER_SEC); __weak typeof(self) weakSelf = self; dispatch_source_set_event_handler(_fastTimer, ^{ __strong typeof(weakSelf) strongSelf = weakSelf; if (!strongSelf) return; // 如果需要更新UI,切换到主线程 dispatch_async(dispatch_get_main_queue(), ^{ strongSelf.roundCount++; if ((strongSelf.roundCount / giftMaxCount == minRoundCount) && strongSelf.startType != 22) { BOOL has = NO; for (NSNumber *index in self.finishTargetArrayIndex) { if (index.integerValue == self.currentIndex) { has = YES; break; } } self.currentGiftView.isSelected = NO; if (has) { QXSkyPraizeSubView *giftView = strongSelf.allViewsArray[strongSelf.currentIndex]; giftView.isSelected = YES; }else{ QXSkyPraizeSubView *giftView = strongSelf.allViewsArray[strongSelf.currentIndex]; giftView.isSelected = NO; } }else{ /// 把上一个选中状态置为未选中 strongSelf.currentGiftView.isSelected = NO; } /// 计算当前下标 strongSelf.currentIndex = strongSelf.roundCount%giftMaxCount; /// 获取当前选中的view 并设置为选中状态 QXSkyPraizeSubView *giftView = strongSelf.allViewsArray[strongSelf.currentIndex]; giftView.isSelected = YES; /// 重新赋值给选中view strongSelf.currentGiftView = giftView; if (strongSelf.roundCount / giftMaxCount == minRoundCount) { /// 已经转了2圈 if (strongSelf.startType == 22) { NSInteger index = strongSelf.targetIndex; // 0 - > 11 // 1 - > 12 // 2->13 // 3->14 // 4->15 // 处理0-4数据无法匹配问题 if (index < 5) { index = (giftMaxCount-1) + index; } if ((strongSelf.currentIndex + toSlowCount) == index) { //距离目标差4 QXLOG(@"当前下标为%ld---目标为%ld",strongSelf.currentIndex,strongSelf.targetIndex); [self stopFastAnimate]; [self startSlowAnimate]; }else{ dispatch_source_set_timer(strongSelf.fastTimer, dispatch_time(DISPATCH_TIME_NOW, 0.06 * NSEC_PER_SEC), DISPATCH_TIME_FOREVER, 0.01 * NSEC_PER_SEC); } }else{ // for (QXSkyPraizeSubView *giftView in strongSelf.allViewsArray) { // giftView.isSelected = NO; // } BOOL has = NO; for (NSNumber *index in strongSelf.targetArrayIndex) { if (strongSelf.currentIndex == index.integerValue) { QXSkyPraizeSubView *giftView = strongSelf.allViewsArray[index.integerValue]; giftView.isSelected = YES; [giftView startPulseAnimationWithLayer]; // [strongSelf pauseGCDTimer]; [strongSelf.targetArrayIndex removeObject:index]; [strongSelf.finishTargetArrayIndex addObject:index]; has = YES; break; } } // dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.3 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ // [strongSelf resumeGCDTimer]; // }); if (has) { dispatch_source_set_timer(strongSelf.fastTimer, dispatch_time(DISPATCH_TIME_NOW, 1 * NSEC_PER_SEC), DISPATCH_TIME_FOREVER, 0.01 * NSEC_PER_SEC); }else{ dispatch_source_set_timer(strongSelf.fastTimer, dispatch_time(DISPATCH_TIME_NOW, 0.06 * NSEC_PER_SEC), DISPATCH_TIME_FOREVER, 0.01 * NSEC_PER_SEC); } if (strongSelf.targetArrayIndex.count == 0) { [strongSelf stopFastAnimate]; } } }else{ dispatch_source_set_timer(strongSelf.fastTimer, dispatch_time(DISPATCH_TIME_NOW, 0.06 * NSEC_PER_SEC), DISPATCH_TIME_FOREVER, 0.01 * NSEC_PER_SEC); } }); }); dispatch_resume(_fastTimer); } -(void)startSlowAnimate{ if (_slowTimer == nil) { _slowTimer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)); } // 立即开始,初始间隔0.1秒 dispatch_source_set_timer(_slowTimer, dispatch_time(DISPATCH_TIME_NOW, self.delayTime * NSEC_PER_SEC), DISPATCH_TIME_FOREVER, // 使用一次性模式 0.01 * NSEC_PER_SEC); __weak typeof(self) weakSelf = self; dispatch_source_set_event_handler(_slowTimer, ^{ __strong typeof(weakSelf) strongSelf = weakSelf; if (!strongSelf) return; // 如果需要更新UI,切换到主线程 dispatch_async(dispatch_get_main_queue(), ^{ /// 把上一个选中状态置为未选中 strongSelf.currentGiftView.isSelected = NO; strongSelf.roundCount++; /// 计算当前下标 strongSelf.currentIndex = strongSelf.roundCount%giftMaxCount; /// 获取当前选中的view 并设置为选中状态 QXSkyPraizeSubView *giftView = strongSelf.allViewsArray[strongSelf.currentIndex]; giftView.isSelected = YES; /// 重新赋值给选中view strongSelf.currentGiftView = giftView; if (strongSelf.currentIndex == strongSelf.targetIndex) { //距离目标差4 QXLOG(@"礼物结束====当前下标为%ld---目标为%ld",strongSelf.currentIndex,strongSelf.targetIndex); [strongSelf stopSlowAnimate]; [strongSelf.currentGiftView startPulseAnimationWithLayer]; } }); strongSelf.delayTime = strongSelf.delayTime+0.1; dispatch_source_set_timer(strongSelf.slowTimer, dispatch_time(DISPATCH_TIME_NOW, strongSelf.delayTime * NSEC_PER_SEC), DISPATCH_TIME_FOREVER, 0.01 * NSEC_PER_SEC); }); dispatch_resume(_slowTimer); } -(void)stopFastAnimate{ if (_fastTimer != nil) { dispatch_source_cancel(_fastTimer); _fastTimer = nil; } } - (void)pauseGCDTimer { if (_fastTimer) { dispatch_suspend(_fastTimer); NSLog(@"GCD定时器已暂停"); } } - (void)resumeGCDTimer { if (_fastTimer) { dispatch_resume(_fastTimer); NSLog(@"GCD定时器已恢复"); } } -(void)stopSlowAnimate{ if (_slowTimer != nil) { dispatch_source_cancel(_slowTimer); _slowTimer = nil; } } -(void)getTargetGift{ self.targetArrayIndex = [NSMutableArray arrayWithArray:@[@3,@5,@8,@10]]; if (self.startType == 22) { self.targetIndex = arc4random() % 12; }else{ // NSNumber *number = self.targetArrayIndex.firstObject; // self.targetIndex = number.integerValue; } } -(void)getTenTargetGift{ } -(NSMutableArray *)allViewsArray{ if (!_allViewsArray) { _allViewsArray = [NSMutableArray arrayWithArray:@[@"",@"",@"",@"",@"",@"",@"",@"",@"",@"",@"",@""]]; } return _allViewsArray; } -(NSMutableArray *)finishTargetArrayIndex{ if (!_finishTargetArrayIndex) { _finishTargetArrayIndex = [NSMutableArray array]; } return _finishTargetArrayIndex; } -(void)showInView:(UIView *)view{ self.bgView.y = SCREEN_HEIGHT; [view addSubview:self]; [UIView animateWithDuration:0.3 animations:^{ self.bgView.y = SCREEN_HEIGHT-ScaleWidth(520)-kSafeAreaBottom; }]; } -(void)hide{ [self stopFastAnimate]; [self stopSlowAnimate]; [UIView animateWithDuration:0.3 animations:^{ self.bgView.y = SCREEN_HEIGHT; } completion:^(BOOL finished) { [self removeFromSuperview]; }]; } @end @implementation QXSkyPraizeSubView - (instancetype)initWithFrame:(CGRect)frame { self = [super initWithFrame:frame]; if (self) { self.backgroundColor = [UIColor cyanColor]; [self initSubviews]; } return self; } -(void)initSubviews{ self.titleLabel = [[UILabel alloc] init]; self.titleLabel.font = [UIFont boldSystemFontOfSize:22]; self.titleLabel.textColor = UIColor.blackColor; self.titleLabel.textAlignment = NSTextAlignmentCenter; [self addSubview:self.titleLabel]; [self.titleLabel mas_makeConstraints:^(MASConstraintMaker *make) { make.edges.equalTo(self); }]; } -(void)setIsSelected:(BOOL)isSelected{ _isSelected = isSelected; self.backgroundColor = isSelected?[UIColor blueColor]:[UIColor cyanColor]; } - (void)startPulseAnimationWithLayer { CABasicAnimation *pulseAnimation = [CABasicAnimation animationWithKeyPath:@"transform.scale"]; pulseAnimation.duration = 0.5; pulseAnimation.fromValue = @0.9; pulseAnimation.toValue = @1.1; pulseAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut]; pulseAnimation.autoreverses = YES; pulseAnimation.repeatCount = HUGE_VALF; // 无限循环 [self.layer addAnimation:pulseAnimation forKey:@"pulse"]; } // 停止动画 - (void)stopPulseAnimationWithLayer { [self.layer removeAnimationForKey:@"pulse"]; } @end