创建一个简单的 iOS 5 iPhone App 教程(2/3)

这个文章是“如何创建一个简单iPhone应用”三部曲的第二部分,这个三部曲主要针对初学者。这个应用是评比最吓人虫子的应用。

在 第一部分, 我们创建了一个应用,它在table view中包含了一系列虫子。

在这个部分文章中,我们会学习如何创建一个详细视图(detail view),在那里可以查看虫子的大图片,给它们打分,替换它们的图片!

在三部曲的 第三部分 , 我们会学习如何添加一个新虫子,给我们工程添加一个图标和缺省图片,和怎么处理长时间运行的操作。

那么让我们开始弄些虫子吧!毕竟,无论什么程序都会有bug吗?:]

ljb_iss
ljb_iss
翻译于 8天前

0人顶

 翻译的不错哦!

View Controllers, 天啊!

现在我们有了一列虫子了,如果点击一个虫子,就弹出一个屏幕可以编辑虫子的名字,图片,评分,那就更好了。

大部分情况下,在iPhone应用中,每一个"界面"(“screen”)都有一个“View Controller”类的对象代表那个界面。现在我们MasterViewController在启动时显示出来了,它包含了一个table view. 我们想当点击一个虫子时,它会打开DetailViewController, 显示这个虫子的一些信息。

当我们第一次运行这个模板工程时,它可以工作,但当我们改变了显示在table view的对象后,点击table view的某一行不再发送正确的对象给detail view(这是我们的bug,不是XCode’s NSDate 工程模板的bug)。我们会回头修复它。

每一个“View Controller”可以包含多个view。在我们的table view controller, 我们只有一个view –  table view. 然而在我们的details view controller, 我们需要一组view – 一个view显示虫子的名字,一个view显示图片,一个view用来评分,和其他的一些view。

ljb_iss
ljb_iss
翻译于 8天前

0人顶

 翻译的不错哦!

下载点材料

说起这个,在详细内容里我们需要一个5星评分视图,但是iPhone默认没有提供。不过我最近写了一个名为《在iOS5里怎样创建自定义UIView:一个5星评分视图》的教程,所以我们在这里重复使用这个教程。

不要太担心这个教程(除非你喜欢这个教程)–相反你只需要下载我放在项目里的 Extra Stuff for Scary Bugs这个包。

继续,下载了这个包之后:

  • 在XCode里创建一个组,命名为Views,然后把 RateView.h/RateView.m拖动到这个组。确保“Copy items into destination group’s folder (if needed)” 复选框被选中。同样要确保target “ScaryBugs” 被选中。这就是教程里五星评分视图的代码。
  • 对UIImageExtras做的操作一样,除了把他们拖动到一个新创建的名为“Helpers”的组 。 这是一些辅助代码,稍后我们调整图片大小时会用到。
  • 对三张震惊表情的脸谱图片重复同样的操作,除了把它们拖到新创建的名为“Art”的组,这些图片是我亲爱的老婆做的。处于幽默的本能,这些图片将被我们用来表示评分视图中的“星星”:]
  • 对logo1.png重复同样的操作,同样拖到“Art”组中,一会我们要用它来设置程序的图标。
人头马没面
翻译于 5天前

0人顶

 翻译的不错哦!

用Storyboard编辑器对我们的Detail View Controller进行布局

好了 – 现在我们终于准备好开始了! 打开MainStoryboard.storyboard, 如果你将滚动条拉到足够靠右的位置,你会看到模板为我们默认生成了Detail View Controller,并且带有一个内容为“Detail view content goes here” 的标签:

创建一个简单的 iOS 5 iPhone App 教程(2/3)_第1张图片

Storyboard编辑器提供了一种可视化的方式,以方便你用XCode构建UI。你可以把UI元素拖放到你的视图上,用你想要的方式设置它们的属性值,甚至你可以在View Controller类里把元素连接到属性。

理解这些最容易的方式是亲自试一下!首先,在view controller上点击一下,并且打开Editor\Canvas\Show Bounds Rectangles(译者注:指的是菜单栏上的Editor) – 这样我们在屏幕上布局控件的时候会容易些。

删除内容为“Detail view content goes here”的标签 – 我们不需要它!

人头马没面
翻译于 5天前

0人顶

 翻译的不错哦!

然后来看面板的右下部分,确保Object Libray的第三个选项卡是被选择了的。拖拽一个UITextField,UIImageView和一个UIView到文字屏幕上并如下图所示安排(文字栏Text Filed在上方)

创建一个简单的 iOS 5 iPhone App 教程(2/3)_第2张图片

然后选择侧边栏上部的UITextField,确保第四个选项卡(属性检查工具)被选择,如此我们可以修改某些属性。

设置字体为Custom\Helvetica\Bold\Size 18.0,文字居中,当编辑时,清除按钮的行为是"Appears While Editing",Capitalzation选择Words,如下

创建一个简单的 iOS 5 iPhone App 教程(2/3)_第3张图片

然后,点击第四个选项卡转到尺寸检查工具(Size Inspector)设置自动大小调整属性。如下

这样当我们的视图(View)旋转到横向显示时,文本框(Text Field)在屏幕上伸展会变得更宽。

renxh_cn
renxh_cn
翻译于 7天前

0人顶

 翻译的不错哦!

下来让我们设置UIImageView. 在等四个tab页(Attributes Inspector) 设置模式为“Aspect Fit”, 在第四个tab (Attributes Inspector) 和第五个tab (Size Inspector) 设置自动缩放(autosizing) 属性为下面的值:

创建一个简单的 iOS 5 iPhone App 教程(2/3)_第4张图片

这会使Image View放大或者缩小时,在保持它的边界到屏幕的边界的距离不变的同时,按照图片的宽高比来缩放图片尽可能的填充可用的空间。

对于UIView, 跳转到第三个tab (Identity Inspector)设置类标示(Class Identity)为“RateView”,我们的五星评分view将显示在那里。然后再第五个tab (Size Inspector) 设置自动缩放(autosizing)属性为下面的值:

这使它缩放时,在保持一样的高度的情况下,左右拉伸。

到现在为止,一切都很棒!下来我们需要添加一些控件到屏幕上,这样用户可以点击UIImageView区域来改变图片。

ljb_iss
ljb_iss
翻译于 4天前

0人顶

 翻译的不错哦!

我们有好几个办法来做实现这个功能,但最简单的一个是创建一个不可见的按钮覆盖在UIImageView上面, 然后设置好按钮点击时的回调函数。我们还可以添加一个UILabel 在图片底层,当没有图片显示时,这个UILabel显示“点击改变图片”(“Tap to Change Picture”).

所以从库里拖拽一个圆角矩形按钮(Round Rect Button),然后调整坐标和UIImageView一样。为了使它不可见,在第四个tab(Attributes Inspector) 修改类型为Custom。然后在第五个tab (Size Inspector)设置自动大小属性为下面的值:

创建一个简单的 iOS 5 iPhone App 教程(2/3)_第5张图片

最后,从库里拖拽一个UILabel, 放在UIImageView中间, 然后双击它编辑文本为"点击改变图片"(“Tap To Change Image.”) 然后修改文本对齐属性(text alignment)为居中(center). 同样在XIB中拖拽UILabel向上几个位置使它可以在UIImageView后面 (这个列表顺序是从底层到上层):

创建一个简单的 iOS 5 iPhone App 教程(2/3)_第6张图片

然后在第五个tab (Size Inspector) 设置自动大小(autosizing)属性为下面的值:

创建一个简单的 iOS 5 iPhone App 教程(2/3)_第7张图片

ljb_iss
ljb_iss
翻译于 4天前

0人顶

 翻译的不错哦!

往下进行前,你可以通过下面的方法再次检查所有的自动大小(autosizing)属性已经正确设置。先选择Detail View Controller, 然后在第四个tab (Attributes Inspector) 把方向从纵向的肖像方式(Portrait)修改为横向的风景画方式( Landscape):

创建一个简单的 iOS 5 iPhone App 教程(2/3)_第8张图片

如果有些地方不对的话,不要担心 – 只需要修改回肖像方式(Portrait)然后再次仔细检查设置。

酷! 我们已经添加完所有需要的控件,然后我们需要把这些控件和我们类中相应的outlet关联起来。

首先,我们要先切换到助手编辑器(Assistant Editor) (点击顶上工具栏“Editor” 段下的第二个按钮), 要确保它设置为Automatic\DetailViewController.h:

ljb_iss
ljb_iss
翻译于 4天前

0人顶

 翻译的不错哦!

然后按着control键,同时鼠标左键拖拽UITextField到DetailViewController.h, 在@end之前释放. 然后会弹出一个弹出窗口让你把UITextField关联到你的类中的一个属性。在名字(Name)编辑框里输入titleField, 然后点击 Connect按钮.

创建一个简单的 iOS 5 iPhone App 教程(2/3)_第9张图片

重复同样的步骤,关联image view (但是关联的outlet命名为imageView),关联Rate View (但是关联的outlet命名为rateView).

我们同样想当按钮点击时,关联到一个我们类的方法被回调。为了实现这个功能,按control键同时,左键拖拽按钮到@end之前 — 就像你关联其他view一样的操作—然而这次connection下拉列表选择Action,在name编辑框输入 addPictureTapped, 然后点击Connect按钮.

创建一个简单的 iOS 5 iPhone App 教程(2/3)_第10张图片

注意,事件(Event)下拉框缺省选择为“Touch Up Inside”。这个缺省选项是对的,因为这意味着,当用户的手指在按钮里面抬起时 (也就是,他们点击了这个按钮), 我们的方法被调用。

ljb_iss
ljb_iss
翻译于 4天前

0人顶

 翻译的不错哦!

你也可以关联其他动作(actions)到回调函数。例如,在文本框的文字改变时会触发一个动作,我们想这时触发一个回调函数。

为了实现这个功能,按control键,拖拽UITextField到@end之前,在弹出窗口,同样设置为动作(Action). 缺省的事件(event)设置为Editing Did End – 修改它为Editing Changed. 修改这个方法的名字(Name)为titleFieldTextChanged, 然后点击Connect按钮.

我们最后要做的一件事是设置我们的类为文本框的委托(delegate)。有时只是接收view的动作的回调是不足够的 - 这些view可能还有些其他信息需要告诉我们,例如这次的文本框就是个例子。

为了实现这个功能,按control键同时点击Text Field,然后从弹出菜单的"delegate"菜单项的右边的小圆圈拖出一条线到Detail View Controller, 然后释放.

创建一个简单的 iOS 5 iPhone App 教程(2/3)_第11张图片

在这时,你的DetailViewController.h应该看起来像下面这样:

01 #import <UIKit/UIKit.h>
02   
03 @interface DetailViewController : UIViewController
04   
05 @property (strong, nonatomic) id detailItem;
06   
07 @property (strong, nonatomic) IBOutlet UILabel *detailDescriptionLabel;
08 @property (weak, nonatomic) IBOutlet UITextField *titleField;
09 @property (weak, nonatomic) IBOutlet RateView *rateView;
10 @property (weak, nonatomic) IBOutlet UIImageView *imageView;
11 - (IBAction)addPictureTapped:(id)sender;
12 - (IBAction)titleFieldTextChanged:(id)sender;
13   
14 @end
你可能注意掉上面有一些特别的类型 – IBOutlet 和 IBAction. 为了关联我们在inerface builder添加的控件到我们类的属性,Storyboard编辑器会查找的 “神奇关键字”。基本上,如果我们把 IBOutlet 或者 IBAction 添加在属性或者方法声明中,Interface Builder 就会探测它们,后续用于联接。
ljb_iss
ljb_iss
翻译于 4天前

0人顶

 翻译的不错哦!

通过Storyboard编辑器创建这些,它已经自动为我们关联好属性和控件了,但你可以按control键同时点击Detail View Controller来查看这些联接. 这些东西叫“outlets” .

我们需要对这部分做一些微调,标志我们的view controller实现了一些代理(delegates); 添加一个属性表示图片选取控件(image picker);和修改我们的detailItem的类型为ScaryBugDoc, 因为这个类型就是我们要显示的详情项。所以最后修改为下面的样子:

01 #import <UIKit/UIKit.h>
02 #import "RateView.h"
03   
04 @class ScaryBugDoc;
05   
06 @interface DetailViewController : UIViewController <UITextFieldDelegate, RateViewDelegate, UIImagePickerControllerDelegate, UINavigationControllerDelegate>
07   
08 @property (strong, nonatomic) ScaryBugDoc * detailItem;
09 @property (strong, nonatomic) IBOutlet UILabel *detailDescriptionLabel;
10 @property (weak, nonatomic) IBOutlet UITextField *titleField;
11 @property (weak, nonatomic) IBOutlet RateView *rateView;
12 @property (weak, nonatomic) IBOutlet UIImageView *imageView;
13 @property (strong, nonatomic) UIImagePickerController * picker;
14   
15 - (IBAction)addPictureTapped:(id)sender;
16 - (IBAction)titleFieldTextChanged:(id)sender;
17   
18 @end
好,设置完布局和头文件了 – 让我们继续完成实现部分吧!
ljb_iss
ljb_iss
翻译于 4天前

0人顶

 翻译的不错哦!

实现详情视图

我要将对 DetailViewController.m 做一些更改。这里的代码较多,那么我们一步一步来看。

1) 导入头文件

1 // 在文件开头
2 #import "ScaryBugDoc.h"
3 #import "ScaryBugData.h"
4 #import "UIImageExtras.h"
5   
6 // 加入同步部分
7 @synthesize picker = _picker;
这个现在你应该已经很清楚了!


2) 设置评分视图

01 // 使用下面代码替换 configureView
02 - (void)configureView
03 {
04     // Update the user interface for the detail item.
05     self.rateView.notSelectedImage = [UIImage imageNamed:@"shockedface2_empty.png"];
06     self.rateView.halfSelectedImage = [UIImage imageNamed:@"shockedface2_half.png"];
07     self.rateView.fullSelectedImage = [UIImage imageNamed:@"shockedface2_full.png"];
08     self.rateView.editable = YES;
09     self.rateView.maxRating = 5;
10     self.rateView.delegate = self;
11 }
在配置视图方法中 (viewDidLoad), 设置我们的 RateView 的属性。 更多详情,查看  How To Make a Custom UIView in iOS 5: A 5-Star Rating View 教程。


3) 启用自动旋转

1 // 使用下面代码替换 shouldAutorotateToInterfaceOrientation :
2 return YES;
在 shouldAutorotateToInterfaceOrientation 中返回 YES 让在 Interface Builder 中设置的大小自动调整属性实现工作! 这将允许用户旋转此视图的方向,控件将使用我们设置的大小自动调属性重新布局。


4) 设置初始 UI 状态

1 // 在配置视图的结束
2 if (self.detailItem) {
3     self.titleField.text = self.detailItem.data.title;
4     self.rateView.rating = self.detailItem.data.rating;   
5     self.imageView.image = self.detailItem.fullImage;
6 }
这里我们简单的通过选中的虫子设置 GUI 属性。


5) 处理文本视图与评分视图

01 - (IBAction)titleFieldTextChanged:(id)sender {
02     self.detailItem.data.title = self.titleField.text;
03 }
04   
05 #pragma mark UITextFieldDelegate
06   
07 - (BOOL)textFieldShouldReturn:(UITextField *)textField {
08     [textField resignFirstResponder];
09     return YES;
10 }
11   
12 #pragma mark RateViewDelegate
13   
14 - (void)rateView:(RateView *)rateView ratingDidChange:(float)rating {
15     self.detailItem.data.rating = rating;
16 }
titleFieldValueChanged 将在用户更改文本编辑视图的值时被调用,所以我们在这里更新对应的模型属性。


textFieldShouldReturn 将在用户按软键盘上的“Return”键时调用,我们调用 resignFirstResponder 隐藏软键盘。

rateView:ratingIsChanged 将在用户选择一个新的评分后通过我们设置的 RateView’s delegate 调用,所以我们在这里更新对应的模型属性。

夜狼
夜狼
翻译于 3天前

0人顶

 翻译的不错哦!

如果您想了解, #pragma marks 是用于 XCode 的特别标记,用于在 XCode 编辑器的函数列表中产生一个用于组织目的的分隔线:

创建一个简单的 iOS 5 iPhone App 教程(2/3)_第12张图片

6) 显示图片选择器和处理返回结果

01 - (IBAction)addPictureTapped:(id)sender {
02     if(self.picker == nil) {  
03         self.picker = [[UIImagePickerController alloc] init];
04         self.picker.delegate = self;
05         self.picker.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
06         self.picker.allowsEditing = NO;   
07     }
08     [self.navigationController presentModalViewController:_picker animated:YES];   
09 }
10   
11 #pragma mark UIImagePickerControllerDelegate
12   
13 - (void)imagePickerControllerDidCancel:(UIImagePickerController *)picker {
14     [self dismissModalViewControllerAnimated:YES];
15 }
16   
17 - (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info {   
18   
19     [self dismissModalViewControllerAnimated:YES];
20   
21     UIImage *fullImage = (UIImage *) [info objectForKey:UIImagePickerControllerOriginalImage];
22     UIImage *thumbImage = [fullImage imageByScalingAndCroppingForSize:CGSizeMake(44, 44)];
23     self.detailItem.fullImage = fullImage;
24     self.detailItem.thumbImage = thumbImage;
25     self.imageView.image = fullImage;
26 }
我们设置 addPictureTapped 在用户点击 UIImage 上的不可见按钮时调用, 在这里我们可以创建 UIImagePicker (如果它还未创建) 并设置图片来源为相册(您当然也可以选择摄像头为来源)。 设置当然类已实现回调委托,那么当用户完成图片选择后我们能通过委托回调得到结果。最后,我们将图片选择器做为一个模式视图控制器压入当前的导航控制器,这意味着它将占据整个屏幕。


最后,我们实现图片选择器的图片已选择与取消回调。无论哪种方式,选关闭(dismiss)模式视图控制器。如果用户选择了一个图片,我们将获取全尺寸的图片和一个缩略图(用之前我们加入的 UIImageExtras 类产生)并同时更新模型与视图。

天啊 - 你看的代码快头疼了?别急 - 我们就快完成了。

夜狼
夜狼
翻译于 3天前

0人顶

 翻译的不错哦!

整合我们的详情视图

这个还是很容易的。首先打开 MainStoryboard.storyboard , 选择 Master View Controller 中的 Table View Cell。Control-drag 这个单元格到 Detail View Controller, 将设置一个弹出选项问您需要使用的连接方式: Push, Modal, 或 Custom 。 选择 Push ,您应该看一个箭头连接了两个视图控制器:

现在我们只需要让选择行的虫子数据传递到详情视图控制器。打开 MasterViewController.m 并做以下更改:

01 // 在文件开头添加
02 #import "DetailViewController.h"
03   
04 // 在 viewWillAppear 中添加
05 [self.tableView reloadData];
06   
07 // 在文件结尾添加
08 - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
09 {
10     DetailViewController *detailController =segue.destinationViewController;
11     ScaryBugDoc *bug = [self.bugs objectAtIndex:self.tableView.indexPathForSelectedRow.row];
12     detailController.detailItem = bug;
13 }
首先,注意在 viewWillAppear 中我们让表格重新加载数据, 这是因为用户进入详情视图后,它可能更改了虫子名称或图片, 我们希望在它们返回列表时能反应名称与图片的更新。简单的方法就是重读整个表格,正如这里做的。
夜狼
夜狼
翻译于 3天前

0人顶

 翻译的不错哦!

下一个,之前我们设置了当行选中时我们 Push 到详情视图控制器到堆。当它发生时将调用 prepareForSegue ,所以我们可以在这里获取详情视图控制器将做任何我们需要的设置。 在这里,我们只需要简单的设置一下选中的虫子。

终于,完成了!编译并运行您的项目,如果一切正常,您将能够进入虫子详情视图,更改虫子的名称、图片并对它们评分,并可能随意旋转您的设备!

创建一个简单的 iOS 5 iPhone App 教程(2/3)_第13张图片


Where To Go From Here?

这里包括完成本教程部分的完成 示例项目 。

如果以上有让你困惑的内容或如果你希望我将一些内容讲得更详细,请告诉我们。

本教程最终部分, 我们将介绍如何添加和删除虫子,添加一个图标和默认图像到我们的项目中,并正确处理长时间运行的操作!

你可能感兴趣的:(创建一个简单的 iOS 5 iPhone App 教程(2/3))