iOS 幸运转盘抽奖+粒子动画

本文介绍了一个iOS平台上的转盘抽奖视图实现方法,通过自定义UIView绘制扇形区域,并利用Core Animation实现了平滑的转盘动画效果。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

前些日子,公司做了个竞猜下注功能。突发奇想,想做一个转盘抽象的功能,于是便有了接下来的demo。

demo地址:  https://github.com/SunshineTraveller/GambleView

思路:

1.根据外界给定数组画对应个数的扇形,然后加到一个父视图上

2.给父视图添加转盘动画


~~~~~~~~~~~~~~~~~~~~~~~~~~begin~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

1.1先画一个扇形,给它起个名叫GambleCell,利用UIBezierPath画几个点,然后闭合上既可

   .h文件

#import <UIKit/UIKit.h>


@interface GambleCell : UIView

/** title */

@property(nonatomic,copy) NSString *title;

@end


.m文件


#import "GambleCell.h"

#import "UIColor+Extension.h"

#import "UIView+Extension.h"



@interface GambleCell ()


/** title */

@property (nonatomic,strong)UILabel  *titleLabel;


@end


@implementation GambleCell


- (instancetype)initWithFrame:(CGRect)frame

{

    self = [superinitWithFrame:frame];

    if (self) {

        [self addSubviews];

    }

    return self;

}


-(void)addSubviews {

    

    // 画扇形

    CAShapeLayer *maskLayer = [[CAShapeLayeralloc] init];

    UIBezierPath *path = [UIBezierPathbezierPath];

    [path moveToPoint:CGPointMake(0,self.frame.size.height)];

    [path addLineToPoint:CGPointMake(self.frame.size.width/2,0)];

    [path addLineToPoint:CGPointMake(self.frame.size.width,self.frame.size.height)];

    [path closePath];

    maskLayer.path = path.CGPath;

    [maskLayer setFillColor:[UIColorblackColor].CGColor];

    self.layer.mask = maskLayer;

    

    UILabel *title = [[UILabelalloc] initWithFrame:CGRectMake(0,self.height-25,self.width,15)];

    title.backgroundColor = [UIColorclearColor];

    title.textAlignment =NSTextAlignmentCenter;

    self.titleLabel = title;

    title.font = [UIFontsystemFontOfSize:12];

    title.textColor = [UIColorcolorWithHexString:@"baa160"];

    [self addSubview:title];

    

}


-(void)setTitle:(NSString *)title {

    self.titleLabel.text = title;

}


@end


1.2 将画好的cell根据外界数组添加到父视图上
1.2.1 父视图
.h文件

#import <UIKit/UIKit.h>


@interface GambleView : UIView


/** finish */

@property(nonatomic,copy) void (^finish)(void);


/**

 * 实例

 * @param frame frame

 * @param colors 颜色数组

 * @return 实例

 */

-(instancetype)initWithFrame:(CGRect)frame colors:(NSArray *)colors;


@end


.m文件

#import "UIView+Extension.h"

#import "GambleCell.h"

#import "GambleView.h"



@interface GambleView ()

/** 颜色数组 */

@property (nonatomic,strong)NSArray *colors;

/** fromValue */

@property (nonatomic,strong)NSNumber *fromValue;


@end


@implementation GambleView


/**

 实例

 

 @param frame frame

 @param colors 颜色数组

 @return 实例

 */

-(instancetype)initWithFrame:(CGRect)frame colors:(NSArray *)colors {

    if (colors.count ==0) return nil;

    self.colors = colors;

    return [selfinitWithFrame:frame];

}


- (instancetype)initWithFrame:(CGRect)frame {

    self = [superinitWithFrame:frame];

    if (self) {

        self.backgroundColor = [UIColoryellowColor];

        self.clipsToBounds =YES;

        [self addGestures];

        [self addSubviews];

    }

    return self;

}


- (void)dealloc

{

    NSLog(@"大转盘销毁了");

}

/**

 * 添加子视图

 */

-(void)addSubviews {

    // 关键点在计算上,要算好扇形实际在圆里的大小

    _fromValue = @(0);

    NSArray *titles =@[@"吃鸡",@"爆头10次",@"吉利服",@"杀10个",@"不被救助",@"杀15个"];

    NSArray *colors = self.colors;

    CGFloat angle = 2*M_PI/colors.count;

    CGFloat r =self.frame.size.height/2;

    CGFloat x = r*sin(angle/2);

    CGFloat y = r*cos(angle/2);

    CGFloat cwid = x/y*r;

    // 将cell添加到俯视图上,这里要根据cell个数绕锚点进行不同角度的旋转,

    for (int i =0; i<colors.count; i++) {

        GambleCell *cell = [[GambleCellalloc] initWithFrame:CGRectMake(0,0,2*cwid,self.frame.size.height/2)];

        cell.title = titles[i];

        cell.layer.position =CGPointMake(self.width/2,self.height/2);

        cell.backgroundColor = colors[i];

        [self addSubview:cell];

        cell.layer.anchorPoint =CGPointMake(0.5,0);

        cell.transform =CGAffineTransformMakeRotation(-angle*i);

    }

    

}


/**

 * 手势

 */

-(void)addGestures {   

     UITapGestureRecognizer *tap = [[UITapGestureRecognizeralloc]initWithTarget:selfaction:@selector(tapAction)];

    [selfaddGestureRecognizer:tap];

}


-(void)tapAction {

    

    // 这里随便给几个数值 让其进行旋转  不用transform动画的原因是:当旋转角度和最终角度位置一样时,不会产生动画

    NSArray  *times =@[@(30),@(31),@(32)];

    NSNumber *time = [times objectAtIndex:arc4random()%3];

       

    CABasicAnimation *baseAni = [CABasicAnimationanimation];

    baseAni.keyPath =@"transform.rotation.z";

    baseAni.duration = time.floatValue/6;

    baseAni.fromValue =_fromValue;

    baseAni.toValue = [NSNumbernumberWithFloat:M_PI/3*time.floatValue];

    baseAni.autoreverses = NO;

    baseAni.removedOnCompletion =NO;

    baseAni.fillMode =kCAFillModeForwards;

    baseAni.timingFunction = [CAMediaTimingFunctionfunctionWithName:kCAMediaTimingFunctionEaseInEaseOut];

    [self.layeraddAnimation:baseAni forKey:@""];

    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(time.floatValue/6 * NSEC_PER_SEC)),dispatch_get_main_queue(), ^{

        if (self.finish) {

            self.finish();

        }

    });

}



VC中调用

NSArray *colors = @[[UIColorredColor],[UIColorblueColor],[UIColoryellowColor],[UIColorcyanColor],[UIColorpurpleColor],[UIColorgreenColor]];

    GambleView *dubo = [[GambleViewalloc] initWithFrame:CGRectMake(80,300, 200, 200) colors:colors];

    dubo.layer.cornerRadius =100;

    [self.viewaddSubview:dubo];

    dubo.finish = ^{

        [selfemitterEffect];

    };

    [self.viewsendSubviewToBack:dubo];

    

    UIImageView *imv = [[UIImageViewalloc] initWithFrame:dubo.frame];

    imv.x += dubo.width/2-10;

    imv.y += 22;

    imv.width = 20;

    imv.height = dubo.height/2-18;

    imv.backgroundColor = [UIColorclearColor];

    imv.image = [UIImageimageNamed:@"pointer"];

    [self.viewaddSubview:imv];

//  转盘结束,加一个简单的粒子动画表示中奖效果,有点low     ~~~~(>_<)~~~~

-(void)emitterEffect {

    

    CAEmitterCell *cell = [[CAEmitterCellalloc] init];

    //展示的图片

    cell.contents = (__bridgeid _Nullable)([UIImageimageNamed:@"gold"].CGImage);

    

    //每秒粒子产生个数的乘数因子,会和layer的birthRate相乘,然后确定每秒产生的粒子个数

    cell.birthRate = 200;

    //每个粒子存活时长

    cell.lifetime = 5.0;

    //粒子生命周期范围

    cell.lifetimeRange =0.3;

    //粒子透明度变化,设置为-0.4,就是每过一秒透明度就减少0.4,这样就有消失的效果,一般设置为负数。

    //    cell.alphaSpeed = -0.2;

    //    cell.alphaRange = 0.5;

    //粒子的速度

    cell.velocity = 40;

    //粒子的速度范围

    cell.velocityRange =20;

    //周围发射的角度,如果为M_PI*2 就可以从360度任意位置发射

    //        cell.emissionRange = M_PI*2;

    //粒子内容的颜色

    //    cell.color = [[UIColor whiteColor] CGColor];

    

    cell.redRange = 0.5;

    cell.blueRange = 0.5;

    cell.greenRange = 0.5;

    

    //缩放比例

    cell.scale = 1;

    //缩放比例范围

    cell.scaleRange = 0.2;

    

    //粒子的初始发射方向

    cell.emissionLongitude =M_PI;

    //Y方向的加速度

    cell.yAcceleration =70.0;

    //X方向加速度

    //    cell.xAcceleration = 20.0;

    

    _emitterLayer = [CAEmitterLayerlayer];

    

    //发射位置

    _emitterLayer.emitterPosition =CGPointMake(SCREEN_WIDTH/2.0,0);

    //粒子产生系数,默认为1

    _emitterLayer.birthRate =1;

    //发射器的尺寸

    _emitterLayer.emitterSize =CGSizeMake(SCREEN_WIDTH,0);

    //发射的形状

    _emitterLayer.emitterShape =kCAEmitterLayerSphere;

    //发射的模式

    _emitterLayer.emitterMode =kCAEmitterLayerOutline;

    //渲染模式

    _emitterLayer.renderMode =kCAEmitterLayerUnordered;

    

    _emitterLayer.zPosition = -1;

    _emitterLayer.emitterCells =@[cell];

    [self.view.layeraddSublayer:_emitterLayer];

    

    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3 * NSEC_PER_SEC)),dispatch_get_main_queue(), ^{

        self.emitterLayer.birthRate =0;

    });

}




demo地址:  https://github.com/SunshineTraveller/GambleView

~~~~~~~~~~~~~~~~~~~~~~~~~~end~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值