引言

原理:利用CoreGraphics进行自定义转盘的绘制

在app侧控制中奖奖品,有两种方式


方式一: 发起网络请求获取当前选中奖品(推荐),即由服务侧控制中奖数据,更安全

方式二:根据奖品百分比进行控制中奖概率


I、根据奖品百分比进行控制中奖概率

  • 根据中奖概率probability 确定随机中奖范围probabilityRange
  • 根据随机中奖范围probabilityRange,确定中奖奖品


iOS抽奖转盘上篇:概率抽奖算法 & 转盘算法 &轮盘边框动画_.net


1.1 定义奖品模型

#import <Foundation/Foundation.h>

NS_ASSUME_NONNULL_BEGIN

@interface KNTurntableViewModel : NSObject
@property (nonatomic, assign) NSInteger index;
@property (nonatomic, copy) NSString *title;
@property (nonatomic, copy) NSString *imageName;

@property (nonatomic, copy) NSString *icon;
/**
该奖品的中奖概率
*/
@property (nonatomic, assign) double probability;

//
@property (nonatomic, assign) NSRange probabilityRange;

/**
根据奖品的中奖概率获取中奖奖品
*/
+(instancetype)getMbyprobabilityRangeWithArr:(NSArray*)arr;

@end

NS_ASSUME_NONNULL_END

1.2 根据奖品的中奖概率获取中奖奖品

  • 根据随机中奖范围probabilityRange,确定中奖奖品
// 根据奖品百分比进行控制:
// 奖品 title A ,index下标0,中奖 概率probability80%, 就是当randomNum为0-80,返回中奖下标0
// 为了便于理解,我们称奖品A的【随机中奖范围】 probabilityRange为0-80
//

// 根据randomNum,确定中奖奖品

+ (instancetype)getMbyprobabilityRangeWithArr:(NSArray *)arr {


NSInteger randomNum = arc4random()%100;//控制概率

NSLog(@"randomNum:%@",[NSNumber numberWithDouble:randomNum]);


for (KNTurntableViewModel *obj in arr) {

NSLog(@"obj probabilityRange loc:%@ len %@", [NSNumber numberWithDouble:obj.probabilityRange.location],[NSNumber numberWithDouble:obj.probabilityRange.location+obj.probabilityRange.length]
);





if (randomNum>=obj.probabilityRange.location && randomNum<obj.probabilityRange.location+obj.probabilityRange.length) {//80%的概率 就是0-80


return obj;


}


}

return nil;// 谢谢参与

}

1.3 构造数据模型

  • 根据中奖概率probability 确定随机中奖范围probabilityRange
- (KNTurntableViewM *)viewModel{

if(_viewModel == nil){
_viewModel = [KNTurntableViewM new];

NSMutableArray * luckyItemArray = [NSMutableArray array];


double probabilityRangeLoc = 0;
double probabilityRangeLen = 0;



for (int i = 0; i < 6; i++) {//
KNTurntableViewModel *model = [[KNTurntableViewModel alloc] init];
model.title = [NSString stringWithFormat:@"%d-标题",i];
model.index = i;
if(i == 1){

model.probability = 0.5;



}else{
model.probability =0.1;

}


// 初始化probabilityRange
probabilityRangeLoc = probabilityRangeLoc +probabilityRangeLen;
probabilityRangeLen = i+100*model.probability;


//probabilityRange 的计算不要包括谢谢参与的概率
model.probabilityRange = NSMakeRange(probabilityRangeLoc, probabilityRangeLen);

model.imageName = @"qrcode_for_gh";
model.icon = @"https://img-blog.csdnimg.cn/20201114103143654.JPG?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3UwMTEwMTg5Nzk=,size_16,color_FFFFFF,t_30#pic_center";


[luckyItemArray addObject:model];


}





_viewModel.luckyItemArray = luckyItemArray;


}

return _viewModel ;
}

II、转盘算法

2.1 旋转到指定下标奖品

  • 旋转到指定下标奖品
/**
转盘算法
*/
- (void)animationWithSelectonIndex:(NSInteger)index{

[self backToStartPosition];



double perSection = M_PI*2/_luckyItemArray.count;

// //先转4圈 再选区 顺时针(所有这里需要用360-对应的角度) 逆时针不需要

double toValue= ((M_PI*2 - (perSection*index +perSection*0.5)) + M_PI*2*4);


[self RotationWithEndValue: @(toValue - M_PI/2) duration:4 delegate:self];// 因为drawRect从正3点开始画,因此- M_PI/2


}

- (void)RotationWithEndValue:(id)toValue duration:(CFTimeInterval)duration delegate:(id)delegate{
CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"transform.rotation"];

animation.toValue = toValue;//

animation.duration = duration;

//由快变慢
animation.removedOnCompletion = NO;
animation.fillMode = kCAFillModeForwards;
animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseOut];//
animation.delegate = delegate;

[self.layer addAnimation:animation forKey:@"rotation"];

}
  • 恢复起始位置
-(void)backToStartPosition{
CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"transform.rotation"];
animation.toValue = @(0);
animation.duration = 0.001;
animation.removedOnCompletion = NO;
animation.fillMode = kCAFillModeForwards;
[self.layer addAnimation:animation forKey:@"rotation"];
}

2.2 处理旋转结束事件

  • CAAnimationDelegate,处理旋转结束事件
#pragma mark - CAAnimationDelegate

- (void)animationDidStart:(CAAnimation *)anim{

}

- (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag{



if (self.rotaryEndTurnBlock) {
self.rotaryEndTurnBlock();
}


}

III、iOS 抽奖轮盘边框动画

原理: 用NSTimer无限替换UIImageView的Image为互为错位的bg_horse_race_lamp_1或者bg_horse_race_lamp_2,达到跑马灯的效果


iOS抽奖转盘上篇:概率抽奖算法 & 转盘算法 &轮盘边框动画_ios_02


iOS抽奖转盘上篇:概率抽奖算法 & 转盘算法 &轮盘边框动画_前端_03

  • 应用场景: iOS 抽奖轮盘边框动画


审核注意事项: 1、在抽奖页面添加一句文案“本活动与苹果公司无关”


2、在提交审核时修改分级至17+

3.1 实现代码

//
// ViewController.m
// horse_race_lamp
//
// Created by mac on 2021/4/7.
#import <Masonry/Masonry.h>


#import "ViewController.h"
NSString *const bg_horse_race_lamp_1=@"bg_horse_race_lamp_1";
NSString *const bg_horse_race_lamp_2=@"bg_horse_race_lamp_2";

@interface ViewController ()
/**

用NSTimer无限替换bg_horse_race_lamp_1和bg_horse_race_lamp_2,达到跑马灯的效果

应用场景: iOS 抽奖轮盘边框动画
*/
@property (nonatomic,strong) UIImageView *rotaryTable;
@property (nonatomic,strong) NSTimer *itemBordeTImer;
@end

@implementation ViewController

- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.


//通过以下两张图片bg_lamp_1 bg_lamp_2,用NSTimer无限替换,达到跑马灯的效果
_rotaryTable = [UIImageView new];
_rotaryTable.tag = 100;

[_rotaryTable setImage:[UIImage imageNamed:bg_horse_race_lamp_1]];

[self.view addSubview:_rotaryTable];

[_rotaryTable mas_makeConstraints:^(MASConstraintMaker *make) {

make.center.offset(0);

}];



_itemBordeTImer = [NSTimer scheduledTimerWithTimeInterval:0.5 target:self selector:@selector(itemBordeTImerEvent) userInfo:nil repeats:YES];


[[NSRunLoop currentRunLoop] addTimer:_itemBordeTImer forMode:NSRunLoopCommonModes];







}
// 边框动画
- (void)itemBordeTImerEvent
{
if (_rotaryTable.tag == 100) {
_rotaryTable.tag = 101;
[_rotaryTable setImage:[UIImage imageNamed:bg_horse_race_lamp_2]];
}else if (_rotaryTable.tag == 101){
_rotaryTable.tag = 100;
[_rotaryTable setImage:[UIImage imageNamed:bg_horse_race_lamp_1]];
}
}




@end

see also

更多内容请关注​​#小程序:iOS逆向​​,只为你呈现有价值的信息,专注于移动端技术研究领域。