写在前面:
刚刚开始学习Swift开发,很幸运的是在网上闲逛的时候看到了Ray Wenderlich的这些关于iOS开发的教程,写的非常详尽,还很有趣,不时会搭配一些很贱的小表情,非常对我的胃口:-)在此对其进行一些翻译,纰漏之处,欢迎大家指正。
——Schuming
Update note: This tutorial was updated for iOS 9 and Swift 2 by Brian Moakley. Original post by Mike Jaoudi and Ry Bristow.
恭喜,你来到了教程系列的第四部分!
在教程的第一部分,你学习了通过Swift语言编程的基础知识,包括变量,if/else语句,循环,可选类型等等.
在教程的第二部分,你将新的Swift技能应用到一个简单的猜数字游戏中.
在教程的第三部分,你创建了一个简单的命令行app来记录people对象的名字和年龄.
在第四部分里,终于要制作你的第一个iPhone App了.
在这个教程中,你将学习到怎么去创建一个叫做Tap Me的游戏!这个游戏的目的是要你在30秒内,尽可能多的点击一个按键.
开始
首先,打开Xcode并选择Create a new Xcode project.
然后,选择 iOS > Application > Single View Application and hit Next.
按照如下内容填写项目选项:
- Product Name: Tap Me
- Organization Name: 这项可以为空,或者你也可以输入你的公司名称
- Organization Identifier: 输入com.yourname, 比如com.rybristow
- Language: Swift
- Devices: iPhone
串连图(Storyboards)
你会注意到,这个项目的初始文件和你的Command Line Tool App有所不同. 你最先关注的应该就是Main.storyboard了.
当你点击这个文件后,你将打开一个图形用户界面(Graphical User Interface,GUI),它显示的是app运行后iPhone将显示的界面.
注意:你可能会奇怪,为什么这个界面看起来是一个正方形,而不是iPhone的尺寸.在iOS开发中,你的目标是将你的apps设计为可以适应不同屏幕的尺寸-这叫做自适应布局(Adaptive Layout).
一般来说,你将会以“远离顶部位置(stay this far away from the top)”或"停留在中心位置(stay centered)"这样的规则来布局你的用户界面中的元素,通过这样的方式,可以让app工作在iPhone5到iPhone 6 Plus等等屏幕大小不一的设备上.
现在,这个app是一片空白的.为了做些改变,你需要确保工具菜单(Utilities Menu)是打开的.选中并打开.
接下来,选择属性检查器(Attributes Inspector)
它可以让你去查看和修改视图控制器(View Controller)中的不同属性.要查看属性,需要先点击view
将背景颜色由白色改为绿色.
现在,在上方的菜单中选择iPhone 6仿真器并运行app-这样你可以看到程序运行后的样子.构建(build)和运行(run)需要花费一段时间,因此要耐心一点.当它最终运行起来后,你应该看到一个弹出的窗口,它是一个正在运行当前app的模拟的iPhone界面.
在界面中添加标签(Adding Labels to the Screen)
绿色的界面看起来不错,但是如果你的界面中没有用户交互的内容,你的app就毫无用处.要添加一些组件,打开工具菜单(Utilities Menu)中的组件库(Object Library).你添加的第一个对象是标签(Label)组件.标签(Label)可以被程序用来承载文本内容.浏览组件库,找到Label.
将它拖拽到界面中并将它布局在顶部的中心位置.
你可以使用属性检查器(Attributes Inspector)来修改Label的标题(title),也就是Label上显示的内同. 将它改为“Time: 30”.
到了这里,你的label可能看起来像是被截掉了一段.为了改变这个情况,点击你的label并选择Editor\Size to Fit (或者敲=号).
现在运行你的app来看一下是这样的.
通过串联图(storyboard), 这个标签看起来没有居中是不是? 这个问题是因为并非每一个iOS设备都有相同的尺寸规格,所以有时候对尺寸的适配会非常混乱.你需要做的就是给label添加一个布局约束(constraint)来保证它处于屏幕的中心位置.
点击Label,然后选择屏幕底部的Align按键并选择Horizontal Center in Container 并且 Add 1 Constraint.
这决定了label在横向上的位置.你还需要选定它在纵向上的位置.点击屏幕底部的Pin,通过红色顶针来固定当前位置与顶部的相对距离,点击 Add 1 Constraint:
添加了布局约束后的label可能会带有一条向外扩展的橙黄色的线.这是因为label的位置跟布局约束建议位置不同产生的.
如果确是这样, 点击右手边稍下面一些的三角型图标(triangle icon) ,在View Controller的All Views中, 选择Update Frames选项.
现在,创建另一个Label对象并将它放置在界面的底部来显示分数.两个不同的地方是,你将希望字体大小(font size)为40,线宽(Lines)为2.将布局(Alignment)设置为中心对齐(Center).
在尺寸检查器中(Size Inspector), 将高度(height)设置为130点高.
你还需要添加一些布局约束(constraints) . 首先你要在横向上将它放置到中心位置.在score label被选中的情况下,点击Align按键,选择Horizontal Center in Container 然后 Add 1 Constraint.
接下来,点击Pin按钮. 添加一个bottom pin, 选择Height. 将Height设置为130.最后的点击 Add 2 Constraints button.
如果你看到橙黄色的线,点击右下角的三角形图标,在All Views in View Controller 部分, 选择 Update Frames 选项:
Build然后 run, 现在你的labels应该很完美的居中了:
添加一个按键
在屏幕上添加最后一个组件.使用Object Library来添加一个组件并把它放到屏幕正中间.
不要忘记给button添加constraints,横向和纵向都放到中心位置.
通过 Attributes inspector 将title改为Tap Me! 并将background设为white.
为了让你的button在白色背景上更醒目一点,你要通过不同的constrains对它进行一些拉伸.这次,要点击Pin然后选择Width和Height方框.将width设置为167,height设置为113.
如果出现了橙黄色的线,就去执行前面说过的Update Frames.
你的button应该是一个块漂亮的并足够大的可点击区域.Build并且run,你的app看起来应该是这样的:
你可以点击button,现在什么都不会发生.我们来做点改变!
关联Views和代码(Linking Views to Code)
现在你已经在Storyboard中排列好了views.你需要将他们与代码关联起来.每个iOS app中的"screen"都由View Controller类控制. Xcode已经在模板中为你创建了一个 – ViewController.swift.在这款游戏里,你得为你的labels在这个类中添加两个属性(properties),这样你就可以通过编程来更新labels.将下面的属性添加到ViewController.swift中的ViewController类中:
@IBOutlet var scoreLabel: UILabel!
@IBOutlet var timerLabel: UILabel!
这两行代码创建了两个UILabel属性.你需要把你在Storyboard中创建的views和这些属性关联起来.通过@IBOutlet 关键词来标记这些属性后,storyboard 编辑器会识别到他们.
注意:你可能注意到了,你在标记这些labels时,在结尾使用了一个感叹号.这是将label声明为隐式解析可选类型(implicitly unwrapped optionals).在你操作这些属性前,编译器会自动解析这些可选类型属性,你可以像操作正常类型的变量一样操作他们(尽管他们是可选类型).
在这里这样做事完全没问题的,因为你一定会将它们赋值给你之前在storyboard中创建的views,所以他们一定不会是nil.
类似的情况,当按键被按下时,你希望调用一个method.因此在 ViewController 类中添加这些代码:
@IBAction func buttonPressed() {
NSLog("Button Pressed")
}
类似于 @IBOutlet, @IBAction会让storyboard 编辑器识别到这些方法, 因此你可以将按键点击事件跟它关联起来.
试着关联这些属性和方法!打开 Main.storyboard, 查看打开的文件树,要链接labels的话,你需要在按住CTRL键的情况下,将文件树的中的View Controller拖拽到Time label顶部.
会弹出一个列有Outlets的黑框.选择timerLabel.这是你之前在ViewController.swift中创建的UILabel组件.
现在为score label重复这个操作,将他与scoreLabel关联起来.
为了将button与buttonPressed()方法关联起来,你需要将刚才的过程反向操作一遍.按住CTRL的情况下,将Storyboard中的button拖拽到文件树中的View Controller上.
然后,选择buttonPressed().
现在,试着运行app并点几下button.通过在buttonPressed()中使用NSLog语句,每次你点击button时,屏幕底部的console上都会有一句输出.
操作Labels
button的真正目的不是向终端中进行输出,而是在每次被点击时,让中心的label显示的次数累加.首先,你要学着怎么操作label中的文本.
有个好消息是-这很简单!将buttonPressed()中的函数体替换为下面的内容:
scoreLabel.text = "Pressed"
现在,当你运行你的app并点击button时,屏幕底部的文本会改变为"Pressed".
为了将这个方法应用到scroeLabel上,让它实时显示分数.你需要再做一点工作:
实时显示分数
为了实时显示分数,你需要先创建一个变量.靠近类代码段的上方,两个 @IBOutlet 声明的下面,创建一个叫做count的属性来实时保存score值.
var count = 0
下一步是向buttonPressed()函数顶部添加一行代码,实现count的加运算.
count++
这行代码是下面的简化版:
count = count + 1
现在将scoreLabel中设置text的语句改为:
scoreLabel.text = "Score \n\(count)"
运行你的app来看一下效果.当你点击button时,屏幕底部的label会实时显示你的分数.你的app正在一步一步编程一个可以真正玩起来的游戏!
使用Timer
为了使timer能正确的服务于app,你需要创建两个属性.其中一个是实时保存seconds的变量,另一个是用来计数的NSTimer.在count的声明下面添加这些声明:
var seconds = 0
var timer = NSTimer()
为了使用这些变量,你需要创建两个方法.第一个是setupGame().在类代码段底部添加这个方法的实现:
func setupGame() {
seconds = 30
count = 0
timerLabel.text = "Time: \(seconds)"
scoreLabel.text = "Score: \(count)"
}
这部分代码会在游戏开始时,将所有变量设置为原始值并更新labels.如果你不包含这部分代码,seconds会一直减小而负于0,分数也会一直增长,游戏永远不会重置.
接下来要在 setupGame() 中做的就是开启 timer. 你需要使用scheduledTimerWithTimeInterval()方法来让控制timer.在setupGame()中添加这些代码:
timer = NSTimer.scheduledTimerWithTimeInterval(1.0, target: self, selector: Selector("subtractTime"), userInfo: nil, repeats: true)
现在,通过添加下面的代码,来保证你在viewDidLoad()方法中调用了setupGame():
setupGame()
下面你要实现的方法叫做 subtractTime(). 你会注意到,你在setupGame()中使用timer时,已经在selector项中使用到了这个字段.它正式指向这个方法的.这个方法会用以减少seconds变量,更新timerLabel,然后在timer变为0时触发一个alert.
你要做一些你所熟知的事了:给seconds做减运算,更新timerLabel,创建一个if语句来处理sceonds变为0的情况.
func subtractTime() {
seconds--
timerLabel.text = "Time: \(seconds)"
if(seconds == 0) {
}
}
首先要向if语句中添加的内容是停止timer,放置计数负于0.添加下面的代码:
timer.invalidate()
Build 并run, 倒计时开始了!
红色警报!
接下来,你要学习怎么操作alerts.当你完成你的alert代码后,应该是这样的:
开始吧.首先要创建一个 UIAlertController. 在if语句中,把这行代码添加到invalidate()后面.
let alert = UIAlertController(title: "Time is up!",
message: "You scored \(count) points",
preferredStyle: UIAlertControllerStyle.Alert)
这行代码决定了alert的样子.它为alert选择了title,message,和style.
接下来,你需要调整button的显示内容和功能.添加一个addAction().在alert声明后添加这行代码.
alert.addAction(UIAlertAction(title: "Play Again", style: UIAlertActionStyle.Default, handler: {
action in self.setupGame()
}))
如果你仔细的研究这行代码,你会发现它使用了title来决定button的显示内容,并且通过handler来让button被按下时调用setupGame()函数.
最后一行代码!这行代码用来告诉app去显示UIAlertController.他使用presentViewController().在alert.addAction(...)后添加这行代码:
presentViewController(alert, animated: true, completion:nil)
现在运行你的第一个iPhone app,尽情的玩吧.你能超过我的分数吗?:]
接下来做些什么
最终的项目代码在这里.
现在准备好学习教程中的下一部分吧.你将学习到怎么更改现在的界面,并让它看起来更吸引人.
有问题的话,欢迎来论坛讨论!