原文链接:http://www.raywenderlich.com/9864/how-to-create-a-rotating-wheel-control-with-uikit
Translated By @youthpasses
或许有时候你下载了一个非常酷的带有一种新颖的用户界面的应用,并且你会想:它是怎么实现的呢?
一个非常典型的例子就转轮,这在CovertBot和其他应用中被作为一个可由用户进行选择的菜单而被采用。
这个控件很自然的会被采用因为他与我们现实生活中要做选择而使用的控件很相似。例如:
l 轮船的舵会由船长来选择航行的方向
l 设置立体声的声音,你要用一个旋钮
l 你也许会记得我们人类以前用旋转号盘电话机打电话
这些现实让我们意识到我们可以使用转轮,即使是一种虚拟的轮子。
注意:对一个物体感知上的使用也叫做功能可见性affordance,是指在某个领域被作为心理学、设计、和人工智能使用的一种概念。
简单的说,一个转轮意味着它是旋转的。正像实物的轮子,触摸屏上的轮子能够以很多的方式实现。比如,我们可能有一个暂停键(类似旋转号盘电话机),在特定区域内忽视了开始键,只允许一个方向的旋转,等等。
正如你所料,这篇教程将会展现你如何做一个转轮的界面。你可以把这个控件并入到你的ios应用中,让别人去想你是怎么实现它的 :-)
Getting Started(开始)
你将要创建的转轮会被分解成几个可选择的扇区,每个扇区代表菜单上的一项。每隔扇区是一个图片,还有一个箭头指向现在被选中的扇区。
在这篇教程的最后,你的转轮看起来会像这样:
这是从用户的角度来看转轮是怎样工作的:
这个轮子不会停在固定的位置,所以它会旋转到任何方向而不是你想要的方向。当用户的手指离开触摸屏的时候,这个控件会检测当前距离外围圆圈左侧“鸟嘴”最近的扇区,并且会调整轮子的中间对准鸟嘴。被选中的扇区将会有一个稍深色的背景。
尽管这个轮子看起来很容易使用并且没有太多的代码,但是在整片教程中仍有一些很重要的知识。你需要熟悉以下方面:
l 建一个自定义组件
l 检测轻拍并计算轻拍点
l 一些基础的三角函数知识
l 把拖拽的手势转换层旋转
l 使用QuartzCore中的affine transformations(仿射变换)
Creating the Control Class(创建这个控件类)
第一步是建一个工程和这个控件的基础类
建这个工程只用Single View Application就足够了。打开XCode,选择IOS\Application\Single View Application 模版建一个新工程。
在下一步的向导中,这样做:
1. 工程名起做“RotaryWheelProject”
2. 设置Class prefix 为“SM”
3. 选择iPhone为模拟设备(不过这个控件也可在iPad上运行)
4. 不选择 Use Storyboard
5. 使用自动引用计数
你最后应得到一个空的工程,包含一个委托和一个空的view controller就像下边的这张图片所示:
现在你处在一个十字路口。为了创建你的新组件,你可以扩张两个类中的一个:UIView或UIControl。
UIControl 继承自UIView,并且from an object-oriented perspective,UIControl更容易扩展成大部分特殊的类。唯一的不同是你必须重写这些方法来获得你想要的行为。在这篇教程中,你将会扩展UIControl,但是如果你选择扩展VIView的话,我会提供相关的说明。
现在,我们已经决定了,用IOS\Cocoa Touch\Objective-C class 模版创建一个新的file。类的名字叫做 SMRotrayWheel,继承自UIControl。
在修改SMRotrayWheel类之前,我们首先增加另一个新文件。这个文件用SMRotaryWheel类定义了一个协议。
再一次创建新file,但是这次我们用IOS\Cocoa Touch\Objective-C protocol模版。给这个协议起个名叫SMRotaryProtocol。
协议的定义相当的简单。用下面的代码代替SMRotaryProtocol.h中的内容:
#import <Foundation/Foundation.h>
@protocol SMRotaryProtocol <NSObject>
- (void) wheelDidChangeValue:(NSString *)newValue;
@end |
当用户的手指离开屏幕的时候这个方法就会被调用,它标志着菜单上一个新的选项被选定了。一会你就会看到我们怎么调用它。
现在转移到SMRotaryWheel.h文件,用下面这条重要的语句导入协议:
#import "SMRotaryProtocol.h" |
然后在@end的上面添加下边的这些properties:
@property (weak) id <SMRotaryProtocol> delegate; @property (nonatomic, strong) UIView *container; @property int numberOfSections; |
这些properties保持对委托的追踪,来获知用户什么时间做出一个选择、包含转轮的容器视图、和转轮视图的扇区数量。
在这些properties的下边,添加下面的方法:
- (id) initWithFrame:(CGRect)frame andDelegate:(id)del withSections:(int)sectionsNumber; |
上面的这个方法会在view controller视图控制器中调用来初始化这个转轮组件。
现在来到SMRotaryWheel.m,用下面的代码替换掉其中的内容:
#import "SMRotaryWheel.h" @interface SMRotaryWheel() - (void)drawWheel; @end @implementation SMRotaryWheel @synthesize delegate, container, numberOfSections; - (id) initWithFrame:(CGRect)frame andDelegate:(id)del withSections:(int)sectionsNumber { // 1 - Call super init if ((self = [super initWithFrame:frame])) { // 2 - Set properties self.numberOfSections = sectionsNumber; self.delegate = del; // 3 - Draw wheel [self drawWheel]; } return self; } - (void) drawWheel { } @end |
到这,你已经添加了一个drawWheel私有方法,声明了三个properties,定义了initWithFrame:andDelegate:withSections:方法,这个方法的参数被保存在properties中。drawWheel方法用来绘出轮子。
注意:你还没有实现绘出轮子的功能,但是你马上就会做了!:-)
现在,编译并运行!很不幸,你现在只得到一个空白的屏幕,但是这有利于检查出你在每个编码阶段所遗漏的程序错误。