原文 : http://www.it165.net/pro/html/201409/21216.html

最终效果图:

各个view的关系图:

背景圆盘(需穴ky"http://www.it165.net/qq/" target="_blank"
class="keylink">qq/2828tKbA7SlMdWNreUJhc2VCYWNrZ3JvdW5kLnBuZzwvc3Ryb25nPjwvcD4KPHA+PGltZyBzcmM9"http://www.it165.net/uploadfile/files/2014/0901/20140901192959329.png"
alt="\">

盖在背景圆盘上面的转盘 LuckyRotateWheel.png


代表一个星座或生肖的按钮背景图片

穴ky"http://www.it165.net/qq/" target="_blank"
class="keylink">qq0tL2oMTK49iyyotLU1+7Pwre91tC1486qw6q147340NDQ/deqPC9zdHJvbmc+PC9wPgo8cD48c3Ryb25nPjxpbWcgc3JjPQ=="http://www.it165.net/uploadfile/files/2014/0901/20140901193000331.png"
alt="\">

对背景圆盘进行扣图,并在其上面盖上转盘图片的核心代码


在自定义的背景view中,画好了背景圆盘和背景转盘之后,

一次性添加12个代表星座或生肖的按钮,并设置旋转角度


一张集合了所有的代表星座的按钮的背景图片的大图片


一张集合了所有的代表星座的按钮的背景图片的大图片


需要根据不同的按钮的i值,

利用CGImageCreateWithImageInRect方法

从大图片中裁剪出一张小图片作为按钮的背景图片


供控制器调用,让圆转盘(circleBgView)慢悠悠地转


当用户点击圆转盘中心的【开始选号】按钮时,

让circleBgView所在图层,利用核心动画CA,

进行假的疯狂地快速旋转,并且动画完成时,

才让cirleBgView的transform真正地旋转负的一定角度,

让被点击的按钮指向正上方


控制器

01.<strong>//
02.//  LuckyNumController.h
03.//  25_彩票
04.//
05.//  Created by beyond on 14-8-27.
06.//  Copyright (c) 2014年 com.beyond. All rights reserved.
07.//
08. 
09.#import <UIKit/UIKit.h>
10. 
11.@interface LuckyNumController : UIViewController
12. 
13.@end
14.</strong>


01.//
02.//  LuckyNumController.m
03.//  25_彩票
04.//
05.//  Created by beyond on 14-8-27.
06.//  Copyright (c) 2014年 com.beyond. All rights reserved.
07.//
08. 
09.#import "LuckyNumController.h"
10.// 两个封装的view
11.// 顶部的三个按钮作为一整体添加到控制器的view
12.#import "TopThreeBtnsAsOne.h"
13.// 中间的所有东东,作为一个整体添加到控制器的view
14.#import "CircleView.h"
15.#import "CircleViewDelegate.h"
16. 
17.@interface LuckyNumController ()<CircleViewDelegate>
18.{
19.TopThreeBtnsAsOne *_threeButton;
20.CircleView *_circle;
21.}
22.@end
23. 
24.@implementation LuckyNumController
25.#pragma mark - 生命周期方法
26.// 控制器的view消失的时候,可以暂停转盘
27.- (void)viewDidDisappear:(BOOL)animated
28.{
29.[super viewDidDisappear:animated];
30. 
31.[_circle pauseRotate];
32.}
33.// 控制器的view出现的时候,才需慢慢转动转盘
34.- (void)viewWillAppear:(BOOL)animated
35.{
36.[super viewWillAppear:animated];
37. 
38.[_circle startSlowlyRotate];
39.}
40. 
41.- (void)viewDidLoad
42.{
43.[super viewDidLoad];
44. 
45.// 1.根据4inch或3.5   添加一个全屏的背景
46.[self setupFullScreenBg];
47. 
48.// 2.添加顶部3个选择按钮作为一个整体
49.[self setupTopThreeBtnsAsOne];
50. 
51.// 3.添加圆转盘整体
52.[self setupCircleView];
53.}
54.// 1.根据4inch或3.5   添加一个全屏的背景
55.- (void)setupFullScreenBg
56.{
57.UIImageView *bg = [[UIImageView alloc] initWithFrame:self.view.bounds];
58.bg.image = [UIImage imageNamed:is4inch?@"LuckyBackground-568h@2x.jpg":@"LuckyBackground@2x.jpg"];
59.bg.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
60.[self.view addSubview:bg];
61.}
62.// 2.添加顶部3个选择按钮作为一个整体
63.- (void)setupTopThreeBtnsAsOne
64.{
65.TopThreeBtnsAsOne *tb = [TopThreeBtnsAsOne threeBtnsAsOne];
66.CGFloat cx = self.view.frame.size.width * 0.5;
67.CGFloat cy = tb.frame.size.height * 0.5 + 20;
68.tb.center = CGPointMake(cx, cy);
69.[self.view addSubview:tb];
70._threeButton = tb;
71.}
72.// 3.添加圆转盘整体
73.- (void)setupCircleView
74.{
75.CircleView *circle = [CircleView circleView];
76.// 设置代理,监听其内部的 12星座或生肖按钮的点击状态
77.circle.delegate = self;
78.// 设置转盘为星座类型 或生肖类型
79.circle.circleType = CircleViewTypeAstrology;
80.circle.circleType = CircleViewTypeAnimal;
81.// 置于顶部的三个按钮的下方
82.CGFloat cx = _threeButton.center.x;
83.CGFloat cy = CGRectGetMaxY(_threeButton.frame) + circle.frame.size.height * 0.5;
84.// 对3.5inch作一个调整
85.if (!is4inch) {
86.// 3.5inch屏幕,往上移动20个点
87.cy -= 20;
88.}
89.circle.center = CGPointMake(cx, cy);
90.[self.view addSubview:circle];
91._circle = circle;
92.}
93. 
94.#pragma mark - 转盘的代理方法 略
95.@end

幸运选号顶部的三个按钮,可作为一整体添加到LuckyNumController控制器中

01.//
02.//  TopThreeBtnsAsOne.h
03.//  25_彩票
04.//
05.//  Created by beyond on 14-8-30.
06.//  Copyright (c) 2014年 com.beyond. All rights reserved.
07.//  幸运选号顶部的 三个按钮,可作为一整体添加到LuckyNumController控制器中
08. 
09.#import <UIKit/UIKit.h>
10. 
11.@interface TopThreeBtnsAsOne : UIView
12. 
13.//  类方法返回 从xib创建的对象
14.+ (instancetype)threeBtnsAsOne;
15.@end
01.//
02.//  TopThreeBtnsAsOne.m
03.//  25_彩票
04.//
05.//  Created by beyond on 14-8-30.
06.//  Copyright (c) 2014年 com.beyond. All rights reserved.
07.//  幸运选号顶部的 三个按钮,可作为一整体添加到LuckyNumController控制器中
08. 
09.#import "TopThreeBtnsAsOne.h"
10. 
11.@interface TopThreeBtnsAsOne()
12. 
13.@end
14. 
15.@implementation TopThreeBtnsAsOne
16. 
17.//  类方法返回 从xib创建的对象
18.+ (instancetype)threeBtnsAsOne
19.{
20.return [[NSBundle mainBundle] loadNibNamed:@"TopThreeBtnsAsOne" owner:nil options:nil][0];
21.}
22. 
23.@end


幸运转盘CircleView,是中部最大的view,

它包括由两个部组成,

分别是一个开始按钮、一个背景层CircleBgView,

其中背景层CircleBgView又包括三层,

分别是图片1圆盘(要扣图),图片2转盘,12个按钮

01.//
02.//  CircleView.h
03.//  25_彩票
04.//
05.//  Created by beyond on 14-8-30.
06.//  Copyright (c) 2014年 com.beyond. All rights reserved.
07.//  幸运转盘CircleView,是中部最大的view,它包括由两个部组成,分别是一个开始按钮、一个背景层CircleBgView,其中背景层CircleBgView 又包括三层,分别是图片1圆盘(要扣图),图片2转盘,12个按钮
08. 
09.#import <UIKit/UIKit.h>
10.@protocol CircleViewDelegate;
11. 
12.// 让控制器可以选择幸运转盘的类型,选择星座 还是生肖,从而其内部会从不同的图片中裁剪一个个小按钮的背景图
13.typedef enum {
14.CircleViewTypeAstrology, // 星座
15.CircleViewTypeAnimal // 生肖
16.} CircleViewType;
17. 
18.@interface CircleView : UIView
19. 
20.// 类方法,返回实例对象
21.+ (instancetype)circleView;
22.// 让控制器可以选择幸运转盘的类型,选择星座 还是生肖,从而其内部会从不同的图片中裁剪一个个小按钮的背景图
23.@property (nonatomic, assign) CircleViewType circleType;
24.// 成员:代理,告诉控制器,内部点击的按钮的切换
25.@property (nonatomic, weak) id<CircleViewDelegate> delegate;
26. 
27.// 开始慢悠悠地转动圆盘
28.- (void)startSlowlyRotate;
29.// 暂停计时器
30.- (void)pauseRotate;
31.// 停止圆盘的转动,并且清空计时器
32.- (void)stopRotate;
33.@end

001.//
002.//  CircleView.m
003.//  25_彩票
004.//
005.//  Created by beyond on 14-8-30.
006.//  Copyright (c) 2014年 com.beyond. All rights reserved.
007.//  幸运转盘CircleView,是中部最大的view,它包括由两个部组成,分别是一个开始按钮、一个背景层CircleBgView,其中背景层CircleBgView 又包括三层,分别是图片1圆盘(要扣图),图片2转盘,12个按钮
008. 
009.#import "CircleView.h"
010.// 背景层CircleBgView 又包括三层,分别是图片1圆盘(要扣图),图片2转盘,12个按钮
011.#import "CircleBgView.h"
012.// 代表一个个星座按钮
013.#import "CircleItem.h"
014.#import "CircleViewDelegate.h"
015. 
016.// 速度 : 1秒种转多少度
017.#define ILCircleRotateSpeedPerSecond (M_PI_4/2)
018.// 从transform用公式 算出角度
019.#define ILTransform2Angle(transform) atan2(transform.b, transform.a)
020. 
021. 
022.@interface CircleView ()
023.{
024.// 背景层CircleBgView,其中背景层CircleBgView 又包括三层,分别是图片1圆盘(要扣图),图片2转盘,12个按钮
025.CircleBgView *_circleBgView;
026.CADisplayLink *_timer;
027.}
028.@end
029. 
030.@implementation CircleView
031.#pragma mark - 生命周期方法
032.+ (instancetype)circleView
033.{
034.return [[self alloc] init];
035.}
036.// 供外部调用,设置【Circle背景View 】上的12个按钮是星座图,还是生肖
037.- (void)setCircleType:(CircleViewType)circleType
038.{
039._circleType = circleType;
040. 
041.// 更换【Circle背景View 】内部要使用的大图片
042.if (circleType ==CircleViewTypeAstrology) {
043.[_circleBgView set12BtnsBgWithBigImg:@"LuckyAstrology" selected:@"LuckyAstrologyPressed"];
044.} else {
045.[_circleBgView set12BtnsBgWithBigImg:@"LuckyAnimal" selected:@"LuckyAnimalPressed"];
046.}
047.}
048.// 初始化内部的子控件:1.开始按钮,2.Circle背景View (圆盘,转盘,12个星座或生肖按钮)
049.- (id)initWithFrame:(CGRect)frame
050.{
051.self = [super initWithFrame:frame];
052.if (self) {
053.//        self.backgroundColor = [UIColor yellowColor];
054.// 1.添加背景层CircleBgView,其中背景层CircleBgView 又包括三层,分别是图片1圆盘(要扣图),图片2转盘,12个按钮
055.[self setupCircleBgView];
056. 
057.// 2.添加浮在圆转盘上面的 开始按钮
058.[self setupStartBtn];
059.}
060.return self;
061.}
062.// 1.添加背景层CircleBgView,其中背景层CircleBgView 又包括三层,分别是图片1圆盘(要扣图),图片2转盘,12个按钮
063.- (void)setupCircleBgView
064.{
065.// 内部固定了宽高
066.CircleBgView *bgView = [CircleBgView circleBgView];
067.[self addSubview:bgView];
068._circleBgView = bgView;
069.}
070.// 2.添加浮在圆转盘上面的 开始按钮
071.- (void)setupStartBtn
072.{
073.UIButton *startBtn = [UIButton buttonWithType:UIButtonTypeCustom];
074.// 开始按钮,位于圆转盘的中心
075.startBtn.bounds = CGRectMake(0, 0, 81, 81);
076.startBtn.center = CGPointMake(self.frame.size.width * 0.5, self.frame.size.height * 0.5);
077.// 设置按钮图片
078.[startBtn setBtnBgImgForNormal:@"LuckyCenterButton" highlightedName:@"LuckyCenterButtonPressed"];
079.// 添加监听事件,开始转动转盘
080.[startBtn addTarget:self action:@selector(startBtnClicked) forControlEvents:UIControlEventTouchUpInside];
081. 
082.[self addSubview:startBtn];
083.}
084. 
085. 
086.#pragma mark - 父类方法
087.// setFrame:和setBounds:能保证尺寸永远是286x286
088.- (void)setFrame:(CGRect)frame
089.{
090.frame.size = CGSizeMake(ILCircleWH, ILCircleWH);
091.[super setFrame:frame];
092.}
093. 
094.- (void)setBounds:(CGRect)bounds
095.{
096.bounds.size = CGSizeMake(ILCircleWH, ILCircleWH);
097.[super setBounds:bounds];
098.}
099. 
100.#pragma mark - 私有方法
101.// 监听【开始按钮】的点击事件,利用CA核心动画,进行假的快速旋转
102.- (void)startBtnClicked
103.{
104.// 0.先清空计时器
105.[self stopRotate];
106. 
107.// 1.停止交互
108.self.userInteractionEnabled = NO;
109. 
110.// 2.利用CA核心动画,进行假的 快速狂转
111.[self crazyRotate];
112. 
113.// 通知代理
114.if ([_delegate respondsToSelector:@selector(circleView:willRoateToIndex:)]) {
115.[_delegate circleView:self willRoateToIndex:_circleBgView.selectedBtn.tag];
116.}
117.}
118.// 2.利用CA核心动画进行假的 狂转
119.- (void)crazyRotate
120.{
121.// 固定写法
122.CABasicAnimation *anim = [CABasicAnimation animationWithKeyPath:@"transform.rotation"];
123.// 从transform用公式 算出角度
124.// #define ILTransform2Angle(transform) atan2(transform.b, transform.a)
125.// 算出被点击的按钮的初始角度
126.CGFloat btnInitialAngle = ILTransform2Angle(_circleBgView.selectedBtn.transform);
127.// 动画持续 时间为2秒
128.anim.duration = 2.0;
129.// 旋转的目标值是  转10圈 - btnInitialAngle
130.anim.toValue = @(M_PI * 20 - btnInitialAngle);
131.// 动画效果  淡进 淡出
132.anim.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
133.// 代理,动画完成后,会通知代理
134.anim.delegate = self;
135.// 让其所在的图层开始假的 快速旋转动画
136.[_circleBgView.layer addAnimation:anim forKey:nil];
137.}
138.#pragma mark - 动画代理方法,动画执行完毕后自动调用
139.- (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag
140.{
141.// 1.允许交互了
142.self.userInteractionEnabled = YES;
143.// 从transform用公式 算出角度
144.// #define ILTransform2Angle(transform) atan2(transform.b, transform.a)
145.// 2. 算出被点击的按钮的初始角度
146.CGFloat btnInitialAngle = ILTransform2Angle(_circleBgView.selectedBtn.transform);
147.// 3. 让被点击的按钮 指向正上方,即让图层 真正地转 负btnInitialAngle度
148._circleBgView.transform = CGAffineTransformMakeRotation(-btnInitialAngle);
149. 
150.// 通知代理(控制器) 被点击的按钮的tag
151.if ([_delegate respondsToSelector:@selector(circleView:didRoateToIndex:)]) {
152.[_delegate circleView:self didRoateToIndex:_circleBgView.selectedBtn.tag];
153.}
154.// 4.继续慢悠悠地转
155.[self performSelector:@selector(startSlowlyRotate) withObject:nil afterDelay:1];
156.}
157. 
158.#pragma mark 供控制器调用,让圆转盘,开始慢悠悠地转
159.- (void)startSlowlyRotate
160.{
161.// NSTimer        只适合做频率比较低的事情
162.// CADisplayLink  适合做频率比较高的事情
163.if (_timer.isPaused) {
164.// 如果CADisplayLink仅仅是暂停状态,那么取消暂停
165._timer.paused = NO;
166.} else {
167.// 先停止旧的 CADisplayLink
168.[_timer invalidate];
169.// 再创建新的 CADisplayLink,每1/60秒,调用一次self的rotating:方法
170._timer = [CADisplayLink displayLinkWithTarget:self selector:@selector(slowlyRotating:)];
171.[_timer addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode];
172.}
173.}
174.// 重点~~~ 慢悠悠地旋转
175.// 1秒调用60次,1/60.0秒调用一次
176.- (void)slowlyRotating:(CADisplayLink *)timer
177.{
178.// 速度 : 1秒种转多少度
179.// #define ILCircleRotateSpeedPerSecond (M_PI_4/2)
180. 
181.// 时间 * 速度 == 角度
182.CGFloat angle = timer.duration * ILCircleRotateSpeedPerSecond;
183. 
184.// 旋转一定的角度
185._circleBgView.transform = CGAffineTransformRotate(_circleBgView.transform, angle);
186. 
187.}
188.// 计时器暂停,便可以暂停圆盘的旋转
189.- (void)pauseRotate
190.{
191.// 暂停计时器 CADisplayLink
192._timer.paused = YES;
193.}
194.// 停止圆盘的转动,并且清空计时器
195.- (void)stopRotate
196.{
197.[_timer invalidate];
198._timer = nil;
199.}
200. 
201. 
202.@end


01.//
02.//  CircleViewDelegate.h
03.//  25_彩票
04.//
05.//  Created by beyond on 14-8-31.
06.//  Copyright (c) 2014年 com.beyond. All rights reserved.
07.//  CircleView
08. 
09.#import <Foundation/Foundation.h>
10.@class CircleView;
11.@protocol CircleViewDelegate <NSObject>
12. 
13. 
14. 
15.@optional
16.- (void)circleView:(CircleView *)circleView willRoateToIndex:(NSUInteger)index;
17.- (void)circleView:(CircleView *)circleView didRoateToIndex:(NSUInteger)index;
18. 
19.@end


幸运转盘CircleView的背景层是:CircleBgView,

其中背景层CircleBgView又包括三层,

分别是图片1(背景圆盘, 要扣图),图片2(带棱角的转盘),12个星座按钮(CircleItem)

01.//
02.//  CircleBgView.h
03.//  25_彩票
04.//
05.//  Created by beyond on 14-8-30.
06.//  Copyright (c) 2014年 com.beyond. All rights reserved.
07.//  幸运转盘CircleView的背景层是:CircleBgView,其中背景层CircleBgView 又包括三层,分别是图片1(背景圆盘, 要扣图),图片2(带棱角的转盘),12个星座按钮(CircleItem)
08.//  背景层(3层:最底部圆盘图片、中间转盘图片、顶部的星座小图片)
09. 
10.#import <UIKit/UIKit.h>
11. 
12.@class CircleItem;
13. 
14.// 在.h文件中声明 变量的存在
15.extern const int ILCircleWH;
16. 
17. 
18. 
19.@interface CircleBgView : UIView
20. 
21.// 类方法,返回一个实例对象
22.+ (instancetype)circleBgView;
23. 
24.// 需要根据不同的按钮的i值,利用CGImageCreateWithImageInRect方法,从大图片中裁剪出一张小图片作为按钮的背景图片
25.- (void)set12BtnsBgWithBigImg:(NSString *)normal selected:(NSString *)selected;
26. 
27.// 供外界访问,其内部的当前被点击中的 星座按钮
28.@property (nonatomic, readonly) CircleItem *selectedBtn;
29. 
30.@end

001.//
002.//  CircleBgView.m
003.//  25_彩票
004.//
005.//  Created by beyond on 14-8-30.
006.//  Copyright (c) 2014年 com.beyond. All rights reserved.
007.//  幸运转盘CircleView的背景层是:CircleBgView,其中背景层CircleBgView 又包括三层,分别是图片1(背景圆盘, 要扣图),图片2(带棱角的转盘),12个星座按钮(CircleItem)
008.//  背景层(3层:最底部圆盘图片、中间转盘图片、顶部的星座小图片)
009. 
010.#import "CircleBgView.h"
011. 
012.// 一个自定义的星座按钮
013.#import "CircleItem.h"
014.// 在.m中定义变量
015.const int ILCircleWH = 286;
016. 
017. 
018.@implementation CircleBgView
019. 
020. 
021.#pragma mark - 生命周期方法
022.// 类方法,返回一个实例对象
023.+ (instancetype)circleBgView
024.{
025.return [[self alloc] init];
026.}
027. 
028.- (id)initWithFrame:(CGRect)frame
029.{
030.self = [super initWithFrame:frame];
031.if (self) {
032.self.backgroundColor = [UIColor clearColor];
033.// 1.添加12个的代表星座或生肖的按钮
034.[self add12Btns];
035.}
036.return self;
037.}
038.// 1.添加12个的代表星座或生肖的按钮
039.- (void)add12Btns
040.{
041.for (int i = 0; i < 12; i++) {
042.// 按钮内部会 设置自己的锚点 btn.layer.anchorPoint = CGPointMake(0.5, 1);
043.// 设置按钮所在图层的锚点(底部中点),坐标系以左上角为 0 0,x向右为正,y向下为正
044.// 目的是让所有的按钮在添加的时候,可以围绕锚点,即大圆图片的中心点进行rotate
045. 
046.CircleItem *btn = [CircleItem buttonWithType:UIButtonTypeCustom];
047.// 绑定tag,目的是要告诉代理,点击了哪一个按钮
048.btn.tag = i;
049. 
050.// 设置每个代表生肖的按钮的位置和角度
051.// 锚点的x在圆盘的中心,锚点的y也在圆盘的中心,仅仅变化的是代表星座的按钮的角度
052.CGFloat posX = ILCircleWH * 0.5;
053.CGFloat posY = posX;
054.btn.layer.position = CGPointMake(posX, posY);
055.// 仅仅根据i,设置每一个代表星座的按钮的旋转角度
056.btn.transform = CGAffineTransformMakeRotation(M_PI / 6 * i);
057.// 监听按钮点击
058.[btn addTarget:self action:@selector(btnClick:) forControlEvents:UIControlEventTouchDown];
059.[self addSubview:btn];
060.// 第0个默认选中
061.if (i == 0) {
062.[self btnClick:btn];
063.}
064.}
065.}
066.// 需要根据不同的按钮的i值,利用CGImageCreateWithImageInRect方法,从大图片中裁剪出一张小图片作为按钮的背景图片
067.- (void)set12BtnsBgWithBigImg:(NSString *)normal selected:(NSString *)selected
068.{
069.// 遍历12个按钮,根据其i值,裁剪不同的位置的小图片,作为其背景图片
070.for (int i = 0; i<12; i++) {
071.CircleItem *btn = self.subviews[i];
072.// 加载大图片
073.UIImage *normalBig = [UIImage imageNamed:normal];
074.// 裁剪小图片 (像素坐标转成点坐标,在retina坐标下,比例因子为2,一个点代表2个像素)
075.CGFloat miniW = normalBig.size.width / 12 * [UIScreen mainScreen].scale;
076.CGFloat miniH = normalBig.size.height * [UIScreen mainScreen].scale;
077.// 根据i值不同,裁剪不同的rect
078.CGRect miniRect = CGRectMake(i * miniW, 0, miniW, miniH);
079.// 创建出小图片
080.CGImageRef miniNormalCG = CGImageCreateWithImageInRect(normalBig.CGImage, miniRect);
081.// 设置裁剪出来的小图片为按钮的背景
082.[btn setImage:[UIImage imageWithCGImage:miniNormalCG] forState:UIControlStateNormal];
083. 
084.// 选中时的背景图片,也是一样的裁剪后,设置到按钮的选中状态下背景图片
085.UIImage *selectedBig = [UIImage imageNamed:selected];
086.CGImageRef miniSelectedCG = CGImageCreateWithImageInRect(selectedBig.CGImage, miniRect);
087.[btn setImage:[UIImage imageWithCGImage:miniSelectedCG] forState:UIControlStateSelected];
088.}
089.}
090.// 三步曲,控制按钮点击时的切换
091.- (void)btnClick:(CircleItem *)btn
092.{
093._selectedBtn.selected = NO;
094.btn.selected = YES;
095._selectedBtn = btn;
096.}
097. 
098.#pragma mark - 父类的方法
099.// setFrame:和setBounds:能保证尺寸永远是286x286
100.- (void)setFrame:(CGRect)frame
101.{
102.frame.size = CGSizeMake(ILCircleWH, ILCircleWH);
103.[super setFrame:frame];
104.}
105. 
106.- (void)setBounds:(CGRect)bounds
107.{
108.bounds.size = CGSizeMake(ILCircleWH, ILCircleWH);
109.[super setBounds:bounds];
110.}
111. 
112.#pragma mark - 重点,绘图
113.// 背景圆盘(需要扣图处理)LuckyBaseBackground.png
114.- (void)drawRect:(CGRect)rect
115.{
116.// 1.画最底部的背景圆盘
117.// 取得当前view的上下文,不须再重新创建上下文对象
118.CGContextRef ctx = UIGraphicsGetCurrentContext();
119.// copy一个ctx对象到栈中,保存现场,并且会复制出一个新的上下文.
120.// 在还原现场之前的所有操作,都将在这个新的上下文中执行
121.CGContextSaveGState(ctx);
122. 
123.// 2.在上下文中画一个小点的圆,并裁剪掉上下文,最后将背景圆盘绘制到稍小的圆形上下文中
124.// 2.1.画一个稍小些的圆
125.CGFloat innerCircleXY = 9;
126.CGFloat innerCircleWH = ILCircleWH - innerCircleXY * 2;
127.CGRect innerCircleRect = CGRectMake(innerCircleXY, innerCircleXY, innerCircleWH, innerCircleWH);
128.// 在上下文中的指定坐标处画一个指定大小的圆
129.CGContextAddEllipseInRect(ctx, innerCircleRect);
130. 
131.// 2.2.裁剪(CGContextClip会把之前所画的剪下来)
132.// 意思是 将上下文中 不属于刚才 画的圆的东东,全部清空(清空小圆以外的东东)
133.// 上下文中现在只剩下一个稍小的圆形了
134.CGContextClip(ctx);
135.// 2.3.将稍大的背景圆盘图片 画到刚才裁剪后的上下文中,即为小圆形的上下文中
136.// (因为小圆形以外的上下文区域 已经被清空了)
137.[[UIImage imageNamed:@"LuckyBaseBackground"] drawInRect:rect];
138. 
139.// 3.为了画下一张转盘图,因为不须要裁剪,所以恢复现场,还原为以前的正常的rect的上下文(没被裁剪的rect)
140.CGContextRestoreGState(ctx);
141. 
142.// 4.画中间的完整的转盘图 到上下文中
143.[[UIImage imageNamed:@"LuckyRotateWheel"] drawInRect:rect];
144.}
145. 
146. 
147.@end

CircleItem继承自按钮,

一个本类实例,就代表着一个可被点击的星座或
生肖

01.//
02.//  CircleItem.h
03.//  25_彩票
04.//
05.//  Created by beyond on 14-8-30.
06.//  Copyright (c) 2014年 com.beyond. All rights reserved.
07.//  CircleItem 继承自按钮,一个本类实例,就代表着一个可被点击的星座 或 生肖
08. 
09.#import <UIKit/UIKit.h>
10. 
11.@interface CircleItem : UIButton
12. 
13.@end

01.//
02.//  CircleItem.m
03.//  25_彩票
04.//
05.//  Created by beyond on 14-8-30.
06.//  Copyright (c) 2014年 com.beyond. All rights reserved.
07.//  继承自按钮,一个本类实例,就代表着一个可被点击的星座 或 生肖
08. 
09.#import "CircleItem.h"
10. 
11.// 生肖 或 星座按钮的宽和高,须与提供的图片一致
12.const int kCircleItemWidth = 68;
13.const int kCircleItemHeight = 143;
14. 
15.@implementation CircleItem
16.#pragma mark - 生命周期方法
17.- (id)initWithFrame:(CGRect)frame
18.{
19.self = [super initWithFrame:frame];
20.if (self) {
21.// 设置按钮选中时的背景
22.[self setBackgroundImage:[UIImage imageNamed:@"LuckyRototeSelected.png"] forState:UIControlStateSelected];
23.// 设置按钮所在图层的锚点(底部中点),坐标系以左上角为 0 0,x向右为正,y向下为正
24.// 目的是让所有的按钮在添加的时候,可以围绕锚点,即大圆图片的中心点进行rotate
25.self.layer.anchorPoint = CGPointMake(0.5, 1);
26.}
27.return self;
28.}
29. 
30.#pragma mark - 父类的方法
31.// 重写setFrame:和setBounds:能保证尺寸永远是68x143
32.- (void)setFrame:(CGRect)frame
33.{
34.frame.size = CGSizeMake(kCircleItemWidth, kCircleItemHeight);
35.[super setFrame:frame];
36.}
37.- (void)setBounds:(CGRect)bounds
38.{
39.bounds.size = CGSizeMake(kCircleItemWidth, kCircleItemHeight);
40.[super setBounds:bounds];
41.}
42.// 中须选中,不要高亮状态
43.- (void)setHighlighted:(BOOL)highlighted {}
44.// 调整按钮的图片的位置
45.- (CGRect)imageRectForContentRect:(CGRect)contentRect
46.{
47.// 获得当前屏幕点的比例,如果是2.0代表retina视网膜屏幕,一个点代表2个像素
48.CGFloat scale = [UIScreen mainScreen].scale;
49.// 获得图片本身的大小,从而进行 缩小 为正常的点坐标
50.CGSize size = [self imageForState:UIControlStateNormal].size;
51. 
52.// 除以比例因子,得到点坐标下的正常的size
53.CGFloat w = size.width/scale;
54.CGFloat h = size.height/scale;
55.// 设置x y坐标
56.CGFloat x = ( contentRect.size.width - w ) * 0.5;
57.CGFloat y = ( contentRect.size.height - h ) * 0.5 - 20;
58.// 返回调整好的图片的frame
59.return  CGRectMake(x, y, w, h);
60.}
61. 
62.#pragma mark - 触摸事件二大方法
63.// 点击按钮的时候必定会调用
64.// 询问鼠标点击的point是否在按钮身上
65.// 如果返回YES,代表point在按钮身上,系统就会让按钮处理点击事件
66.// 如果返回NO,代表point部在按钮身上,系统就不会让按钮处理点击事件
67.- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event
68.{
69.NSLog(@"----%@", NSStringFromCGPoint(point));
70.return [super pointInside:point withEvent:event];
71.}
72.- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
73.{
74.return [super hitTest:point withEvent:event];
75.}

【转】iOS25彩票 幸运转盘的更多相关文章

  1. iOS_25彩票_幸运转盘

    终于效果图: 各个view的关系图: 背景圆盘(须要扣图处理)LuckyBaseBackground.png 盖在背景圆盘上面的转盘 LuckyRotateWheel.png watermark/2/ ...

  2. [iOS UI进阶 - 2.4] 彩票Demo v1.4 转盘动画

    A.需求 幸运广场界面中有一个幸运转盘,平时能够自动缓缓转动 能够选择星座 点击“开始选号”开速旋转转盘,旋转一定周数 转盘转动速度节奏:开始-慢-块-慢-结束 设置其余的背景和按钮   code s ...

  3. 【彩票】彩票预测算法(一):离散型马尔可夫链模型C#实现

    前言:彩票是一个坑,千万不要往里面跳.任何预测彩票的方法都不可能100%,都只能说比你盲目去买要多那么一些机会而已. 已经3个月没写博客了,因为业余时间一直在研究彩票,发现还是有很多乐趣,偶尔买买,娱 ...

  4. jQuery刮彩票兑奖效果

    效果体验:http://keleyi.com/a/bjad/uaq24pxt.htm 其中拖拽刮涂层效果使用jquery UI的draggable方法,请参考:http://keleyi.com/a/ ...

  5. JavaScript 实现彩票中随机数组的获取

    1.效果图: <!DOCTYPE html> <html lang="en"> <head> <meta charset="UT ...

  6. EX14 彩票中奖 (lottery.pas/c/cpp)

    [题目描述]小明想试试运气去购买彩票,所以他开始研究彩票大乐透的玩法:超级大乐透是指由购买者从01—35共35个号码中选取5个号码为前区号码,并从01—12共12个号码中选取2个号码为后区号码组合为一 ...

  7. JS产生随机一注彩票

    <!DOCTYPE html><html lang="en"><head>    <meta charset="UTF-8&qu ...

  8. 【目录】C#搭建足球赛事资料库与预测平台与彩票数据分析目录

    本博客所有文章分类的总目录链接:本博客博文总目录-实时更新 1.彩票数据分析与预测 6.智彩足球技术研究团队成员介绍 5.关于组建“智彩足球技术研究团队”的说明 4.为什么选择玩足球彩票以及玩彩票的心 ...

  9. IOS彩票第一天基本框架搭建

    *****初始化 - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionar ...

随机推荐

  1. bzoj3083 3306

    又见bzoj的语言歧视,囧……bzoj3083过了本地的数据在上面出现各种奇葩的TLE835083 phile 3083 Time_Limit_Exceed 17092 kb 4872 ms Pasc ...

  2. Node.js权威指南 (1) - Node.js介绍

    1.1 Node.js概述 / 2 1.1.1 使用Node.js能够解决什么问题 / 2 1.1.2 实现高性能服务器 / 2 1.1.3 非阻塞型I/O及事件环机制 / 2 1.1.4 Node. ...

  3. 6N137的使用

    (1)引脚图 (2)功能表 (3)内部结构图 信号从2.3脚输入,反向偏置的光敏二极管受光照后导通,经过电流电压转换,输入到与门一端,与门另一端为使能端.由于输入信号为集电极开路,需要加上拉电阻.当使 ...

  4. Linq中小心使用IndexOf

      我们平常在做字符串的模糊查询时,有可能会用到下面的类似LINQ写法: string.IsNullOrEmpty(_SN) ? true : a.SN.IndexOf(_SN) != -1   这条 ...

  5. js遍历数组和遍历对象的区别

    <script> //----------------for用来遍历数组对象-- var i,myArr = [1,2,3]; for (var i = 0; i < myArr.l ...

  6. duang体加班版

    领导第一次让我加班的时候,其实我是拒绝的,因为我觉着加班这个事,不能你让我加我就加,晚了就没有地铁了..领导跟我说可以打车报销.加了一个月之后,我的钱包duang~,后来我知道报销其实是假的,我每天打 ...

  7. Java做界面的感想。。

    我用Swing做出的例子: JavaFX做出的界面: 后来又做出了自己编写的一套基于Synth的L&F,其与直接在代码中重绘某个组件不同,最大优点是具有可插拔性,即在不改变原有程序代码的情况下 ...

  8. reloadData should be in main thread

    reloadData should be called in main thread, so if you call it in work thread, you should call it as ...

  9. 【Lucene3.6.2入门系列】第15节_SolrJ高亮

    package com.jadyer.solrj; import java.util.ArrayList; import java.util.List; import java.util.Map; i ...

  10. postgresql的/d命令

    ostgreSQL-psql常用命令 文章索引 [隐藏] \d命令 \d命令   1 2 3 格式: \d [ pattern ] \d [ pattern ] + 该命令将显示每个匹配关系(表,视图 ...