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

最终效果图:

【转】iOS25彩票 幸运转盘-LMLPHP

各个view的关系图:

【转】iOS25彩票 幸运转盘-LMLPHP

背景圆盘(需穴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

【转】iOS25彩票 幸运转盘-LMLPHP

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

穴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="\">

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

【转】iOS25彩票 幸运转盘-LMLPHP

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

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

【转】iOS25彩票 幸运转盘-LMLPHP

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

【转】iOS25彩票 幸运转盘-LMLPHP

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

【转】iOS25彩票 幸运转盘-LMLPHP

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

利用CGImageCreateWithImageInRect方法

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

【转】iOS25彩票 幸运转盘-LMLPHP

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

【转】iOS25彩票 幸运转盘-LMLPHP

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

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

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

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

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

【转】iOS25彩票 幸运转盘-LMLPHP

控制器

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?@"[email protected]":@"[email protected]"];
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


【转】iOS25彩票 幸运转盘-LMLPHP

幸运转盘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.}
05-11 13:02