ios 轉(zhuǎn)盤抽獎(jiǎng)demo

規(guī)則要求:

  • 每個(gè)獎(jiǎng)品有中獎(jiǎng)概率和獎(jiǎng)品的個(gè)數(shù),當(dāng)獎(jiǎng)品個(gè)數(shù)達(dá)到一定的數(shù)值時(shí)扎运,中獎(jiǎng)概率會(huì)發(fā)生變化瑟曲。
  • 轉(zhuǎn)盤轉(zhuǎn)動(dòng)到哪個(gè)獎(jiǎng)品的區(qū)域,即為抽中該獎(jiǎng)品豪治。

想法:

  • 每個(gè)獎(jiǎng)品有個(gè)中獎(jiǎng)區(qū)間洞拨,使用簡(jiǎn)單的隨機(jī)數(shù)算法arc4random獲得一個(gè)隨機(jī)數(shù),如果該數(shù)落在了該中獎(jiǎng)區(qū)間负拟,則是中獎(jiǎng)扣甲。
  • demo是用指針轉(zhuǎn)動(dòng)的方式完成,選中了獎(jiǎng)品之后齿椅,用動(dòng)畫使指針轉(zhuǎn)動(dòng)到對(duì)應(yīng)的扇形區(qū)域琉挖。(如果不想指針轉(zhuǎn),轉(zhuǎn)盤轉(zhuǎn)動(dòng)也是同樣的道理)
  • 還有一些獎(jiǎng)品是有數(shù)量限制的涣脚,剩余量達(dá)到一定的數(shù)量之后示辈,就需要改變?cè)摢?jiǎng)品的中獎(jiǎng)概率了(demo中主要是用中獎(jiǎng)區(qū)間的大小來(lái)表示)。而且為了簡(jiǎn)單化遣蚀,整個(gè)demo的區(qū)間長(zhǎng)度不變矾麻,將某個(gè)“謝謝惠顧”的中獎(jiǎng)區(qū)間擴(kuò)大(后來(lái)發(fā)現(xiàn)改變整個(gè)demo的區(qū)間長(zhǎng)度,好像也是一樣的)芭梯。

數(shù)據(jù)存儲(chǔ)

[minIndex, maxIndex} 是為中獎(jiǎng)區(qū)間险耀,他們的值由中獎(jiǎng)概率和整個(gè)demo的區(qū)間長(zhǎng)度決定。isProbabilityChage表示中獎(jiǎng)概率是否會(huì)發(fā)生改變玖喘,是甩牺,概率數(shù)組才有存在的價(jià)值。因?yàn)楦怕蕯?shù)組probabilityArray存儲(chǔ)的是一個(gè)model累奈,所以需要在.m文件中贬派,顯式表示轉(zhuǎn)換(使用MJExtension)。

/**
 中獎(jiǎng)的model
 */
@interface LotteryModel : NSObject
@property (copy, nonatomic) NSString *name;     //獎(jiǎng)品名稱
@property (assign, nonatomic) NSInteger index;  //獎(jiǎng)品的下標(biāo),唯一
@property (copy, nonatomic) NSDecimalNumber *probability;   //概率
@property (assign, nonatomic) NSInteger count;         //剩余張數(shù) -1為無(wú)窮張
@property (assign, nonatomic) BOOL isProbabilityChage; //概率是否隨張數(shù)改變澎媒。
@property (copy, nonatomic) NSMutableArray *probabilityArray;   //isProbabilityChage = YES 時(shí)有用
@property (assign, nonatomic) NSInteger minIndex;           //中獎(jiǎng)最小值搞乏,包括
@property (assign, nonatomic) NSInteger maxIndex;           //中獎(jiǎng)的最大值,不包括
@end

#import "LotteryModel.h"
#import "MJExtension.h"
#import "MaxProModel.h"
@implementation LotteryModel
- (instancetype)init {
self = [super init];

if (self) {
    [LotteryModel mj_setupObjectClassInArray:^NSDictionary *{
        return @{
                 @"probabilityArray" : [MaxProModel class]
                 };
    }];
}

return self;
}
@end

/**
 動(dòng)態(tài)概率的model
 */
@interface MaxProModel : NSObject
@property (assign, nonatomic) NSInteger maxCount;//當(dāng)張數(shù)=maxCount時(shí)戒努,中獎(jiǎng)概率為maxProbability
@property (copy, nonatomic) NSDecimalNumber *maxProbability;
@end

數(shù)據(jù)處理

創(chuàng)建數(shù)據(jù)方式如下(dict基本都是這么創(chuàng)建请敦,只截取部分):

- (void)initData {
_dataArray = [NSMutableArray new];
NSDictionary *dict4 = @{
                        @"name" : @"謝謝惠顧",
                        @"index" : @3,
                        @"probability" : [NSDecimalNumber decimalNumberWithString:@"0.125"],
                        @"count" : @-1,
                        @"isProbabilityChage" : @0,
                        };
NSDictionary *dict5 = @{
                        @"name" : @"499元XX牌電冰箱購(gòu)買券",
                        @"index" : @4,
                        @"probability" : [NSDecimalNumber decimalNumberWithString:@"0.05"],
                        @"count" : @51,
                        @"isProbabilityChage" : @1,
                        @"probabilityArray" : @[
                                @{
                                    @"maxCount" : @10,
                                    @"maxProbability" : [NSDecimalNumber decimalNumberWithString:@"0.02"]
                                    },
                                @{
                                    @"maxCount" : @20,
                                    @"maxProbability" : [NSDecimalNumber decimalNumberWithString:@"0.025"]
                                    },
                                @{
                                    @"maxCount" : @50,
                                    @"maxProbability" : [NSDecimalNumber decimalNumberWithString:@"0.030"]
                                    }
                                ]
                        };
NSArray *array = @[dict1, dict2, dict3, dict4, dict5, dict6, dict7, dict8];
_dataArray = [LotteryModel mj_objectArrayWithKeyValuesArray:array];

//設(shè)置整個(gè)demo的區(qū)間長(zhǎng)度
_lotteryCount = 10000
NSInteger min = 0;

//設(shè)置每個(gè)獎(jiǎng)品中獎(jiǎng)區(qū)間
for (int i = 0; i < _dataArray.count; i++) {
    LotteryModel *model = _dataArray[i];
    model.minIndex = min;
    model.maxIndex = model.minIndex + [model.probability floatValue] * _lotteryCount;
    min = model.maxIndex;
}
}

用戶點(diǎn)擊抽獎(jiǎng)之后,獲得一個(gè)隨機(jī)數(shù),然后判斷隨機(jī)數(shù)落入那個(gè)獎(jiǎng)品的中獎(jiǎng)區(qū)間內(nèi)侍筛。如果獎(jiǎng)品有數(shù)量限制的萤皂,則需要將獎(jiǎng)品數(shù)減一,并且要判斷是否需要改變?cè)摢?jiǎng)品的中獎(jiǎng)概率勾笆。然后使用動(dòng)畫敌蚜,讓指針指向該獎(jiǎng)品對(duì)應(yīng)的扇形區(qū)域桥滨。

- (IBAction)startLotteryButtonTouch:(UIButton *)sender {
NSInteger index = arc4random() % _lotteryCount;

for (LotteryModel *model in _dataArray) {
    if (index >= model.minIndex && index < model.maxIndex) {
        _selectedModel = model;
        
        if (![model.name isEqualToString:@"謝謝惠顧"]) {
            NSLog(@"恭喜窝爪,您抽中了%@,快點(diǎn)去購(gòu)買商品吧", model.name);
            
            if (model.count != -1 && model.count > 1) {
                model.count -= 1;
            }
            
            //修改中獎(jiǎng)概率
            [self changeProbabilityWithModel:model];
            //顯示動(dòng)畫
            [self showAnimationWithSelectedModel:model];
            break;
        }
        else {
            NSLog(@"%@", model.name);
            
            //顯示動(dòng)畫
            [self showAnimationWithSelectedModel:model];
            break;
        }
    }
}
}

對(duì)于可以修改概率的獎(jiǎng)品,根據(jù)概率數(shù)組對(duì)應(yīng)的概率修改齐媒,并修改該獎(jiǎng)品的概率區(qū)間蒲每。

- (void)changeProbabilityWithModel:(LotteryModel *)model {
//獎(jiǎng)品已經(jīng)沒(méi)有了,需要將獎(jiǎng)品的中獎(jiǎng)區(qū)間改為0
if (model.count == 0) {
    //修改其他的中獎(jiǎng)區(qū)間
    [self changeRandomWithIndex:model.index changeCount:model.maxIndex - model.minIndex];
    
    //中獎(jiǎng)區(qū)間為0
    model.minIndex = model.maxIndex;
}

//如果概率可以改變
if (model.isProbabilityChage) {
    for (MaxProModel *maxModel in model.probabilityArray) {
        if (model.count == maxModel.maxCount) {
            NSInteger changeCount = ([model.probability floatValue] - [maxModel.maxProbability floatValue]) * _lotteryCount;
            
            //修改其他的中獎(jiǎng)區(qū)間
            [self changeRandomWithIndex:model.index changeCount:changeCount];
            
            //縮小中獎(jiǎng)區(qū)間
            model.minIndex += changeCount;
            model.probability = maxModel.maxProbability;
            break;
        }
    }
}
}

/**
重新設(shè)置中獎(jiǎng)區(qū)間
 @param index       index前的數(shù)據(jù)才需要設(shè)置
 @param changeCount index對(duì)應(yīng)的數(shù)據(jù)的區(qū)間減少量
 */
- (void)changeRandomWithIndex:(NSInteger )index changeCount:(NSInteger)changeCount {
//數(shù)據(jù)問(wèn)題喻括,第二個(gè)間隔是不中獎(jiǎng)的邀杏,所以就增大該間隔的中獎(jiǎng)區(qū)間
for (int i = 1; i < index; i++) {
    //將model的區(qū)間減小,增加第一個(gè)獎(jiǎng)品的中間區(qū)間(第一個(gè)獎(jiǎng)品就是不中獎(jiǎng))
    LotteryModel *model = _dataArray[i];
    
    if (i > 1) {
        model.minIndex += changeCount;
    }
    
    model.maxIndex += changeCount;
}
}

轉(zhuǎn)動(dòng)角度_angle唬血, M_PI / count是為了最后能指向中獎(jiǎng)扇形區(qū)域的中間位置望蜡。model.index * 2 * M_PI / count 是確定了中獎(jiǎng)區(qū)間的扇形的起始位置。后面再加幾個(gè)圓周是為了讓指針轉(zhuǎn)動(dòng)多幾圈拷恨。

- (void)showAnimationWithSelectedModel:(LotteryModel *)model {
_lotteryButton.enabled = NO;

NSInteger count = _dataArray.count;
NSInteger current = 8;
_angle = M_PI / count + model.index * 2 * M_PI / count + current * 2 * M_PI;

CABasicAnimation *layer = [CABasicAnimation animationWithKeyPath:@"transform.rotation"];
layer.toValue = @(_angle);
layer.duration = _angle / (3 * M_PI);
layer.removedOnCompletion = NO;
layer.fillMode = kCAFillModeForwards;
layer.repeatCount = 0;
layer.delegate = self;

[_lotteryImageView.layer addAnimation:layer forKey:nil];
}

然后在指針動(dòng)畫停止的方法中脖律,延遲2秒,使指針回到最初的位置腕侄,可以再次抽獎(jiǎng)小泉。并且在中獎(jiǎng)之后彈出中獎(jiǎng)的彈框。

#pragma mark - CAAnimationDelegate
- (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag {
//顯示中獎(jiǎng)彈窗
[self showAlertView];
//設(shè)置指針?lè)祷爻跏嘉恢?[self backToStartPosition];
}

- (void)backToStartPosition {
CABasicAnimation *layer = [CABasicAnimation animationWithKeyPath:@"transform.rotation"];
layer.toValue = @(0);
layer.duration = 0.01;
layer.removedOnCompletion = NO;
layer.fillMode = kCAFillModeForwards;
layer.beginTime = CACurrentMediaTime() + 2; //延遲1S后執(zhí)行
[_lotteryImageView.layer addAnimation:layer forKey:nil];
_lotteryButton.enabled = YES;
}

界面效果:

(轉(zhuǎn)盤是一張圖片冕杠,指針也是一張圖片微姊,指針圓形區(qū)域上面覆蓋著一個(gè)按鈕,點(diǎn)擊按鈕分预,指針就開(kāi)始轉(zhuǎn)動(dòng)兢交。)


轉(zhuǎn)盤.png

demo (<--這是個(gè)跳鏈啊)上傳到百度云了,喜歡的自己去下載吧

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末笼痹,一起剝皮案震驚了整個(gè)濱河市魁淳,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌与倡,老刑警劉巖界逛,帶你破解...
    沈念sama閱讀 219,270評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異纺座,居然都是意外死亡息拜,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,489評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)少欺,“玉大人喳瓣,你說(shuō)我怎么就攤上這事≡薇穑” “怎么了畏陕?”我有些...
    開(kāi)封第一講書人閱讀 165,630評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)仿滔。 經(jīng)常有香客問(wèn)我惠毁,道長(zhǎng),這世上最難降的妖魔是什么崎页? 我笑而不...
    開(kāi)封第一講書人閱讀 58,906評(píng)論 1 295
  • 正文 為了忘掉前任鞠绰,我火速辦了婚禮,結(jié)果婚禮上飒焦,老公的妹妹穿的比我還像新娘蜈膨。我一直安慰自己,他們只是感情好牺荠,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,928評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布翁巍。 她就那樣靜靜地躺著,像睡著了一般休雌。 火紅的嫁衣襯著肌膚如雪灶壶。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書人閱讀 51,718評(píng)論 1 305
  • 那天挑辆,我揣著相機(jī)與錄音例朱,去河邊找鬼。 笑死鱼蝉,一個(gè)胖子當(dāng)著我的面吹牛洒嗤,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播魁亦,決...
    沈念sama閱讀 40,442評(píng)論 3 420
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼渔隶,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了洁奈?” 一聲冷哼從身側(cè)響起间唉,我...
    開(kāi)封第一講書人閱讀 39,345評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎利术,沒(méi)想到半個(gè)月后呈野,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,802評(píng)論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡印叁,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,984評(píng)論 3 337
  • 正文 我和宋清朗相戀三年被冒,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了军掂。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,117評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡昨悼,死狀恐怖蝗锥,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情率触,我是刑警寧澤终议,帶...
    沈念sama閱讀 35,810評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站葱蝗,受9級(jí)特大地震影響穴张,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜垒玲,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,462評(píng)論 3 331
  • 文/蒙蒙 一陆馁、第九天 我趴在偏房一處隱蔽的房頂上張望找颓。 院中可真熱鬧合愈,春花似錦、人聲如沸击狮。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 32,011評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)彪蓬。三九已至寸莫,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間档冬,已是汗流浹背膘茎。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 33,139評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留酷誓,地道東北人披坏。 一個(gè)月前我還...
    沈念sama閱讀 48,377評(píng)論 3 373
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像盐数,于是被迫代替她去往敵國(guó)和親棒拂。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,060評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容

  • 有個(gè)朋友需要寫個(gè)抽獎(jiǎng)大轉(zhuǎn)盤的功能玫氢,就讓我?guī)兔懥讼轮闾搿N矣昧?種方法實(shí)現(xiàn)了效果,在這里和大家一起分享下漾峡。 一攻旦、一鍵轉(zhuǎn)...
    干不動(dòng)閱讀 15,294評(píng)論 10 41
  • 用canvas寫了一個(gè)簡(jiǎn)單的轉(zhuǎn)盤抽獎(jiǎng)插件, 給大家參考下下生逸。牢屋。掰邢。 做的時(shí)候的想法是,通過(guò)傳進(jìn)來(lái)的標(biāo)簽以及屬性伟阔,直接...
    我愛(ài)吃花牛閱讀 2,829評(píng)論 0 5
  • 前段時(shí)間公司里為了推廣微信公眾號(hào)吸粉辣之,需要在公眾號(hào)菜單里增加一個(gè)大轉(zhuǎn)盤抽獎(jiǎng)的活動(dòng),在活動(dòng)現(xiàn)場(chǎng)手機(jī)上抽到什么獎(jiǎng)品就是...
    IT小C閱讀 18,997評(píng)論 1 8
  • 最近的一個(gè)業(yè)務(wù)需求是開(kāi)發(fā)一個(gè)抽獎(jiǎng)管理功能皱炉,要求在一個(gè)獎(jiǎng)池中放一堆獎(jiǎng)品怀估,分別給它們?cè)O(shè)置不同的數(shù)量和概率,在獎(jiǎng)品沒(méi)有發(fā)...
    codemarker閱讀 23,054評(píng)論 2 12
  • 文/sgasun 阿貴與阿毛合搅,你看多搀,這兩名字放在一起,要多般配就有多般配灾部,一看就天生一對(duì)康铭。 和“楊老頭”夫婦一樣,...
    sgasun閱讀 217評(píng)論 -2 2