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