前些日子,公司做了个竞猜下注功能。突发奇想,想做一个转盘抽象的功能,于是便有了接下来的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
#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
#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();
}
});
}
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~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~