【转】iOS25彩票 幸运转盘

原文 : 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. }

转载于:https://www.cnblogs.com/A--G/p/4739152.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值