在这一课中,你会继续在FoodTracker菜谱的场景工作。你会重新安排现有的UI元素并使用图像采集器添加到照片用户界面。当你完成,你的应用程序将是这个样子:

学习目标

在课程结束时,你将能够:

了解视图控制器的生命周期,如viewDidLoad,viewWillAppear和viewDidAppear这些回调函数
在视图控制器之间传递数据
让一个视图控制器消失
使用手势识别生成一个事件
预测的基于UIView/ UIControl类层次的对象行为
使用asset目录,添加图像资源到项目中

理解视图控制器的生命周期

到目前为止,FoodTracker应用程序有一个单一的场景,其用户界面是由一个单一视图控制器管理。为了打造更复杂的应用程序,你会要处理更多的场景,并需要管理载入和卸载在屏幕上来来去去的Views

UIViewController类(及其子类)的对象提供了一组方法,这些方法管理其视图层次结构。当一个视图控制器的状态在转变时,iOS会在适当的时间自动调用这些方法。当你创建一个视图控制器子类,它继承了的UIViewController中定义的方法,让你为每种方法添加自己的自定义行。重要的是要了解,当这些方法被调用,这样你就可以在适当的步骤下设置或拆卸你正在展示的Views,将来你会需要做这些事情。这里可以和Android中的Activity的生命周期做对比

UIViewController的方法调用如下:

viewDidLoad()----当视图控制器的内容视图(顶层视图)被创建并且从一个storyboard载入后调用。这个方法适用于初始化设置,然而,因为由于APP中的资源限制可能会让views被清除,不能保证这个方法只被调用一次

viewWillAppear()---在view可见之前发生的行为。因为一个view的可见度能开关或被其他Views遮蔽,在内容视图出现在屏幕之前,这个方法会立即调用

viewDidAppear()---用于view一可见你就想要发生的操作,如获取数据或显示动画。因为一个view的可见度能开关或被其他Views遮蔽,所以这个方法在内容视图出现在屏幕后会立即调用

另外与之对应的还有一套对立的方法存在,如上面状态图所示。

你会在FoodTracker APP中适当的时间内使用一些方法来载入和显示view数据。实际上,如果你有印象,我们已经写过viewDidLoad()方法中的一些处理

override func viewDidLoad() {
super.viewDidLoad() // Handle the text field’s user input through delegate callbacks.
nameTextField.delegate = self
}

在你的views和数据模型之间,视图控制器作为通信管道, APP这种设计风格被称为MVC(模型-视图-控制器)。在这个模式中,模型跟踪你的app数据,视图显示你的用户界面,并组成一个内容,控制器管理你的views。通过相应用户的动作并且从数据模型得来的内容以填充view。对于任意iOS app来说MVC是一个至关重要的好的设计,到目前为止,FoodTracker一直沿用MVC规则构建。在app剩余的设计中,在头脑里保持MVC模式,是时候把基础的UI带到下一水平了,我们会为菜谱场景创建最终的布局

添加一张菜谱的图片

接下来的是完成菜谱场景的UI,我们添加一个方法来显示一张具体的菜谱照片。为此,我们将使用Image View(弄过android的是不是很熟悉?),这里iOS中使用的是UIImageView类,这是一个UI元素用来显示一张图片,步骤如下:

1.打开storyboard,Main.stroyboard

2.打开实用区域的对象库(也可以选择View > Utilities > Show Object Library)

3.在对象库中,输入image view来快速过滤出你想要的对象

4.拖动Image View到场景中,在我们先前按钮控件的下方

5.选中ImageView,打开Size inspector,你可以调整ImageView的大小和位置

6.在下方的Intrinsic Size字段,选择Placeholder

7.在上方View和下方的Placeholder中都Width和Height中输入320,然后按下Return,因为一个空的iamge view没有内在大小,你给定image view的placeholder大小,然后可以在界面中指定适当的约束

8.在画布的底部右边,点击Pin按钮

9.选择Aspect Ratio复选框,如下所示:

10.在Pin菜单中,点击Add 1 Constraints

你的图片现在是1:1的长宽比,所以他看起来会是个正方形

11.选择image view,打开Attributes inspector

12.在Attributes inspector中,找到Mode然后点击下拉列表,选择Aspect Fill

这个选项有助于确保不同尺寸的图像在image view中不会失真。

13.在Attributes inspector中,找到Interaction ,然后选中User Interaction Enabled复选框

稍后,你将需要此功能,让用户与image view交互。现在的UI应该如下所示:

显示一个默认照片

用户需要一个指示,让他们知道可以和image view交互,并能选择一张照片。要做到这一点,需要添加一个默认placeholder图像,来传达给用户,他们能选择一个照片

你可以点击这里下载我们这章所需要的图片。下面让我们来添加图片到项目中

1.在项目导航中,选择Assets.xcassets(不同Xcode版本,名字可能不一样,有的也许是Images.xcassets)进入asset目录,这个目录是存储你图片的地方

2.在顶部角落,点击+按钮并选择New Image Set

3.然后在出现的Image上,双击,重命名为defaultPhoto

4.在你的电脑中,找到这个图片。

5.然后拖动到x2位置出,放下

2x是 iPhone 6模拟器下的分辨率,图片放在这个位置最佳

接下来我们要在image view中显示默认图片

a.打开你的storyboard

b.在storyboard中选择image view

c.选中image view的情况下打开Attributes inspector

d.在Attributes inspector中找到Image字段,然后选择defaultPhoto

运行你的APP,效果如下:

将Image View连接到代码

现在,你需要实现必要的功能,来在运行时改变图片。你希望能从代码中改变图片,为此,你首先需要在ViewController.swift中连接image view到代码:

1.点击Assistant打开assistant editor

2.如果你想要更多的工作空间,你可以折叠 project navigator和utility area

3.在storyboard中,选择image view

4.按住Control键拖动image view画布到右边的代码编辑器中,选择outlets,如下图:

5.在弹出的对话框中,Name:photoImageView:

6.点击Connect。Xcode会添加必要的代码到ViewController.swift中

你现在能访问iamge view了,从代码上来改变图像,但你如何知道何时改变图片?你需要给用户一个方式来告诉他们可以改变图片。例如,点击image view。然后你要定义一个动作方法来处理点击事件。

views和controls之间有微妙的区别,view有一个特定的版本来响应用户的动作。一个视图显示内容,然而control会以某种方式来修改它,一个control(UIControl)是UIView的子类。实际上,你已经使用过了,例如Views(标签,image view),controls(文本框,按钮)

创建一个手势识别

一个image view不是一个控制,所以它不会像按钮那样被设计为能响应输入。例如,当一个用户点击image view时你不能简单的创建一个动作方法来触发一个事件。(如果你试图按住Control键拖动iamge view到你的代码中,你会发现,在Connection字段后面,它不能选择Action)

幸运的是,它可以很容易的给定一个view添加一个手势识别,作为和控制的能力。手势识别是一个可以附加到view上的对象,view可以响应动作。手势识别可以解释触摸来确定它们是否对应于特定的手势,诸如滑动,挤压或旋转。你能写一个动作方法,用来处理当手势识别发现它对应的手势时,这正是你需要为image view做的

我们可以附加一个点击手势识别(UITapGestureRecognizer)到image view中,当一个用户轻击image view时,它将会识别。你能在storyboard轻松搞定这件事。步骤如下:

1.打开Object library

2.输入tap gesture快速过滤出我们想要的识别事件对象

3.拖动Tap Gesture Recognizer到场景中,放在 image view的上方一点

这个Tap Gesture Recognizer会出现在菜谱的场景Dock中

将手势识别连接到代码中

现在连接手势识别到一个动作方法中。步骤如下:

1.按住Control键拖动手势识别到代码编辑器,然后在//MARK:Action放下

2.在弹出的对话框中,Connection字段旁,选择Action

3.Name字段旁,输入selectImageFromPhotoLibrary

4.Type旁,选择UITapGestureRecognizer

5.点击Connect或按下Return

创建一个图片选择器来响应用户的轻击事件

那么什么时候用户会轻击image view,据推测,用户应该能用照片集中选择一个照片。幸运的是,UIImagePickerController已经把这种行为内置到里面了。一个图片选择器控制者管理一个UI,用于拍照并选择保存图像。正如你在文本框工作时需要一个文本框委托一样,你需要一个图片选择控制器委托来帮助你图片选择控制器的工作。这个委托的是一个协议(UIImagePickerControllerDelegate),你在ViewController定义这个图片选择控制器委托对象。首先ViewController需要采用UIImagePickerControllerDelegate协议。因为ViewController将掌管图片选择控制器的展示,同时我们还需要采用UINavigationControllerDelegate协议,该协议只是让ViewController获取一些基本的导航职责。接下来让我们添加这两个协议:

1.返回standard editor

2.在项目导航中,选择ViewController.swift

3.在ViewController.swift中,找到class这行:

class ViewController: UIViewController, UITextFieldDelegate {

4.然后添加如下代码:

class ViewController: UIViewController, UITextFieldDelegate, UIImagePickerControllerDelegate, UINavigationControllerDelegate {

接下来我们需要实现selectImageFromPhotoLibrary()方法了

a .在ViewController.swift中找到selectImageFromPhotoLibrary()动作方法

@IBAction func selectImageFromPhotoLibrary(sender: UITapGestureRecognizer) {
}

b.在方法体中,添加如下代码:

// Hide the keyboard.
nameTextField.resignFirstResponder()

该方法是确保,用户在点击image view时,如果软键盘正输入打开状态,需要关闭它

c.添加代码,来创建一个图片选择控制器

// UIImagePickerController is a view controller that lets a user pick media from their photo library.
let imagePickerController = UIImagePickerController()

d.然后添加这行代码:

// Only allow photos to be picked, not taken.
imagePickerController.sourceType = .PhotoLibrary

这行代码是设置图片选择控制器的源,或者是它获取图片的地方。.PhotoLibrary选项表示使用模拟器的相机胶卷,这个imagePickerController.sourceType是UIImagePickerControllerSourceType中的一个类型。它是一个枚举。意思是你能写缩写形式.PhotoLibrary来代替UIImagePickerControllerSourceType.PhotoLibrary

e.添加如下代码设置图片选择控制器的委托为ViewController:

// Make sure ViewController is notified when the user picks an image.
imagePickerController.delegate = self

f.最后加上这一行

presentViewController(imagePickerController, animated: true, completion: nil)

presentViewController(_:animated:completion:)是ViewController中调用的方法,虽然这个方法没有显式的写入,但方法会在隐式的self对象上执行。改方法询问ViewControllerto出示imagePickerController定义的视图控制器,animated为true表示图像选择控制器是否以动画呈现。completion表示当此方法执行完后,执行一个关包。因为不需要做任何事,所以这个参数传nil即可。你完整的selectImageFromPhotoLibrary()方法应该如下所示:

@IBAction func selectImageFromPhotoLibrary(sender: UITapGestureRecognizer) {
// Hide the keyboard.
nameTextField.resignFirstResponder() // UIImagePickerController is a view controller that lets a user pick media from their photo library.
let imagePickerController = UIImagePickerController() // Only allow photos to be picked, not taken.
imagePickerController.sourceType = .PhotoLibrary // Make sure ViewController is notified when the user picks an image.
imagePickerController.delegate = self presentViewController(imagePickerController, animated: true, completion: nil)
}

在图片选择控制器展现完后,它的行为会交给委托。给用户选择图片的能力,你需要实现UIImagePickerControllerDelegate中的两个委托方法

func imagePickerControllerDidCancel(picker: UIImagePickerController)
func imagePickerController(picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : AnyObject])

其中第一项,imagePickerControllerDidCancel(_:),让你得到当用户点击图片选择器的取消按钮的调用。这种方法给你一个机会让UIImagePickerController消失。实现如下:

func imagePickerControllerDidCancel(picker: UIImagePickerController) {
// Dismiss the picker if the user canceled.
dismissViewControllerAnimated(true, completion: nil)
}

第二项,imagePickerController,当用户选择一个照片时调用。这种方法可以让你有机会在用户从选择器中选择一个或多个图像时做些什么。在本例中,我们会采取选定的图像,并在UI中显示。实现如下

func imagePickerController(picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : AnyObject]) {
// The info dictionary contains multiple representations of the image, and this uses the original.
let selectedImage = info[UIImagePickerControllerOriginalImage] as! UIImage // Set photoImageView to display the selected image.
photoImageView.image = selectedImage // Dismiss the picker.
dismissViewControllerAnimated(true, completion: nil)
}

第一行代码表示info字典包含你选中原始图像,如果存在,是已编辑的图片版本。为了简单,我们将使用原始的,未经编辑的图片作为菜谱照片。我们把这个照片存储在selectedImage常量中。

第二行代码表示我们给前面的场景中的image view设置它的image

第三行代码当然是让图片选择器消失啦

检查点:运行你的应用程序。你应该可以点击Image View 查看图像选择器。系统会有一个权限警告,询问许可给FoodTracker应用程序访问照片,点击OK即可。然后,您可以点击取消按钮关闭选择器,或打开相机胶卷并单击图像来选择它,并在Image View中显示

如果你通过在模拟器中发现没有任何照片的话。你可以直接添加自己的图像到模拟器来测试。前面Image View中的默认图文件夹中,附带了一张菜谱的图片。你把图片直接从电脑上拖入模拟器即可

和View Controllers一起工作的更多相关文章

  1. 【IOS笔记】Resource Management in View Controllers

    Resource Management in View Controllers 视图控制器的资源管理 View controllers are an essential part of managin ...

  2. 【IOS笔记】Creating Custom Content View Controllers

    Creating Custom Content View Controllers 自定义内容视图控制器 Custom content view controllers are the heart of ...

  3. iOS Programming Autorotation, Popover Controllers, and Modal View Controllers

    iOS Programming Autorotation, Popover Controllers, and Modal View Controllers  自动旋转,Popover 控制器,Moda ...

  4. View Controller Programming Guide for iOS---(五)---Resource Management in View Controllers

    Resource Management in View Controllers View controllers are an essential part of managing your app’ ...

  5. View Controller Programming Guide for iOS---(四)---Creating Custom Content View Controllers

    Creating Custom Content View Controllers 创建自定义内容视图控制器 Custom content view controllers are the heart ...

  6. Presenting view controllers on detached view controllers is discouraged <CallViewController: 0x14676e240>.

    今天在优化app时,发现程序出现这种警告:“ Presenting view controllers on detached view controllers is discouraged <C ...

  7. 更轻量的 View Controllers

    iew controllers 通常是 iOS 项目中最大的文件,并且它们包含了许多不必要的代码.所以 View controllers 中的代码几乎总是复用率最低的.我们将会看到给 view con ...

  8. 【IOS笔记】Using View Controllers in Your App

    参考:http://www.cnblogs.com/patientAndPersist/p/3279645.html Using View Controllers in Your App Whethe ...

  9. iphone dev 入门实例2:Pass Data Between View Controllers using segue

    Assigning View Controller Class In the first tutorial, we simply create a view controller that serve ...

随机推荐

  1. js之函数

    1.倒计时定时器 timename=setTimeout("function()",delaytime); clearTimeout(timename); 2.循环定时器 time ...

  2. lvs主备可以自由切换,vip落在主上的时候,端口无法telnet,业务连接不了

    lvs主备可以自由切换,vip落在主上的时候,端口无法telnet,业务连接不了 解决:将主上的keepalived重启,故障解除 原因:不可知 lvs常见故障原因: real server上的脚步没 ...

  3. (转)CSS 为不同大小的浏览器视窗使用不同的样式表

    转自:http://www.iefans.net/liulanqi-shichuang-butong-yangshibiao/ 同一个网站,访问它的浏览器可能会是不同的宽度,常见的有320px,480 ...

  4. Piggy-Bank(HDU 1114)背包的一些基本变形

    Piggy-Bank  HDU 1114 初始化的细节问题: 因为要求恰好装满!! 所以初始化要注意: 初始化时除了F[0]为0,其它F[1..V]均设为−∞. 又这个题目是求最小价值: 则就是初始化 ...

  5. Robots on a grid(DP+bfs())

    链接:http://www.bnuoj.com/bnuoj/problem_show.php?pid=25585 Current Server Time: 2013-08-27 20:42:26 Ro ...

  6. line-height,vertical-align及图片居中对齐问题根源解析

    关于图片居中对齐的问题,进入前端行业虽然有一段时间了,以为自己懂了,可是实际上还是一知半解,找了一些博客来看了一下,但是感觉讲的有点碎,看完还是一知半解. 查阅了一下<css权威指南>,结 ...

  7. 记一次数据库调优过程(IIS发过来SQLSERVER 的FETCH API_CURSOR语句是神马?)

    记一次数据库调优过程(IIS发过来SQLSERVER 的FETCH API_CURSOR语句是神马?) 前几天帮客户优化一个数据库,那个数据库的大小是6G 这麽小的数据库按道理不会有太大的性能问题的, ...

  8. Dynamic CRM 2013学习笔记(十二)实现子表合计(汇总,求和)功能的通用插件

    上一篇 Dynamic CRM 2013学习笔记(十一)利用Javascript实现子表合计(汇总,求和)功能 , 介绍了如何用js来实现子表合计功能,这种方法要求在各个表单上添加js方法,如果有很多 ...

  9. ubuntu apache2 wsgi 部署django

    入题 分为如下几步 1.安装python 2.安装django 3.安装wsgi,如有问题请参照上一篇 ubuntu 编译安装 mod_wsgi 4.与apache集成这里主要讲这部分 环境apach ...

  10. 自己动手写UI库——引入ExtJs(布局)

    第一: 来看一下最终的效果 第二: 来看一下使用方法: 第三: Component类代码如下所示: public class Component     {                   pub ...