Files
midi_ios/QXLive/活动/QXSkyPraizeView.m
2025-08-18 15:23:07 +08:00

460 lines
18 KiB
Objective-C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

//
// 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()<UIGestureRecognizerDelegate>
/// 目标下标
@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