http://www.ibm.com/developerworks/cn/xml/x-iosslideshow/
创建用于 iPad 的 iOS 幻灯片应用程序
常用缩写词
- IDE:集成开发环境
- iOS:苹果的移动操作系统
- OS X:苹果用于 Macintosh计算机的操作系统
为 iOS 设备如 iPad 或 iPhone 编写应用程序是非常受欢迎的活动,这毫不奇怪。这些设备华丽且易于使用。这些设备拥有数百万的用户,为这些设备开发应用程序利润可观。人们喜欢在 iPad 和 iPhone 靓丽的屏幕上观看自己的照片。
在本文中,我们将学习如何从头开始创建 iOS 照片幻灯片应用程序。您要将一些 XML 代码和照片放在服务器上,创建 iOS 应用程序,添加一个图像视图,获取 XML,并制作幻灯片动画。
示例幻灯片应用的后端实际上只是一个 XML 文件,您可以将其放在服务器上。清单 1 显示了示例 XML 以及一些示例图像。
清单 1. photos.xml
<photos> <photo url="http://localhost/photos/CRW_0675.jpg" /> <photo url="http://localhost/photos/CRW_1488.jpg" /> <photo url="http://localhost/photos/CRW_3273.jpg" /> <photo url="http://localhost/photos/CRW_3296.jpg" /> <photo url="http://localhost/photos/CRW_3303.jpg" /> <photo url="http://localhost/photos/CRW_3359.jpg" /> <photo url="http://localhost/photos/CRW_3445.jpg" /> <photo url="http://localhost/photos/CRW_3752.jpg" /> <photo url="http://localhost/photos/CRW_3754.jpg" /> <photo url="http://localhost/photos/CRW_4525.jpg" /> <photo url="http://localhost/photos/CRW_4547.jpg" /> <photo url="http://localhost/photos/CRW_4700.jpg" /> <photo url="http://localhost/photos/CRW_4860.jpg" /> </photos> |
这个 XML 非常简单。<photos> 标记包含多个 <photo> 标记。每个 <photo> 标记包含您想显示的图像的 URL。该 URL 必须完全合格和绝对;客户端应用程序将直接加载该 URL,而不是通过处理相对 URL 的任何类型的浏览器。
要完成后端,请修改该 XML 来包括对您的照片的引用,并将该 XML 加载到您的服务器上的一个已知的位置。如果一切都按计划进行,那么您应该能够浏览到该 XML,使用 Safari 执行(或您选择的任何浏览器),并看到图 1 所示的内容。
图 1. 服务器上的 XML
图 1显示了清单 1 中的 XML 为文本格式。每个浏览器的结果都不同,因为这只是一个简易的 XML(浏览器之间没有标准)。要验证这些 URL 是否正确:
- 选择其中一个 URL。
- 将其复制并粘贴到浏览器的 URL区域。
- 按Rreturn键。
您应看到与 图 2 相似的内容。图 2. 服务器上的一张照片
位于服务器的一张照片被 XML 中的一个 URLs 引用。如果您没有看到该 XML,或者没有看到照片,那么您需要检查您的 Web 服务器配置和您的 URL。如果您在浏览器中无法看到照片,那么您的新 iOS 应用程序也无法看到照片。
在配置完服务器并上传了照片后,您就可以开始创建 iOS 应用程序。第一步是安装 Apple Developer 工具(参见参考资料 中的链接)。如果:
- 您是 Pre-Lion,那么您需要从 Apple Developer网站下载开发工具(参见参考资料中的链接)。
- 您是 Running Lion,那么您可以使用 Mac App Store下载这些工具(参见参考资料中的链接)。
在安装了开发工具后,运行 XCode 环境,它是 Apple 用于开发 iOS 和 Mac OS X 的 IDE。从 XCode 环境中,选择New Project 的菜单选项。您应该看到应用程序向导的第一页,您将使用该应用程序的向导创建 iOS 或 Mac OS X 应用程序,如图 3 所示。
图 3. 应用程序向导
您可以从多个不同的应用模板进行选择。对于该示例,选择View-based Application,然后单击 Next。您应看到向导的最后一页,如 图 4 所示。
图 4. 项目选项
在向导的第二页,命名您的应用程序并选择默认的设备系列(iPad 或 iPhone)。该示例应用程序的 “项目名称” 为slideshow
。Company Identifier 字段的值表示应用程序位于 com.jherrington
命名空间。(当然,您可以选择您喜欢的任何名称和公司标识。)为 Device Family(设备系列)选择iPad,然后点击 Next。
项目创建完成。此时,最好选择界面左上角的较大的 Play 按钮,从而首次运行您的应用程序。这一步骤编译了所有内容并引入了 iPad 模拟器。
下一步是添加图像视图用于显示图像。iOS 框架提供了一套丰富的内置控件,可用来创建您的应用程序。对于该示例,您将使用 UIImageView 控件。通过使用 UIImageView 您可以显示那些编译到应用程序的图像,本地存储在设备中的图像,或者,如该示例所示,从网站下载的图像。
要添加 UIImageView,请打开 slideshowControllerView.XIB 文件,它是 slideshowControllerView 的用户界面定义文件。打开 XIB 后,请在对象面板选择Image View,如 图 5 所示。
图 5. 将 UIImageView 对象添加到视图控制器 XIB
选择了 Image View 后,将其拖放到 slideshowControllerView。通常,IDE 会自动缩放控件的尺寸,使其适应可用的空间。如果没有进行缩放,则只须拖动控件并调整其大小,直到它填满了整个显示区域。
当该控件出现在视图上后,设置某些参数获得应用程序的最佳外观和感受。图 6 显示了 Image View 控件的属性屏幕上的设置。
图 6. 配置 UIImageView
您需要执行的两个修改分别是 “模式” 和 “背景”。将 “模式” 设置为Aspect Fit,以便缩放该图像但仍保留其原始的宽高比。如果您不想使用 Aspect Fit,您的图像将拉伸和缩放,以匹配图像视图的显示区域,最终看起来非常棒。
由于图像可能并不总是适合可用的区域,您还需要将 Background 属性设置为Dark Text Color 或使用颜色选择器选择深黑色。在默认情况下,该值为白色。大多数照片当放在亮白框架里时效果都不好。
保存 XIB 文件,并移动到 SlideshowViewController.h 文件。进行小改动,如清单 2 所示。
清单 2. SlideshowViewController.h
#import <UIKit/UIKit.h> @interface slideshowViewController : UIViewController { IBOutlet UIImageView *imgView; } @end |
您需要将 Outlet
添加到slideshowViewController
,以允许在 XIB 中定义的控件连接到视图控制器类。
在添加了出口后,返回到 XIB 文件,选择 UIImageView,使用连接检查器将 UIImageView 对象连接到slideshowViewController
类中的 imgView
变量。
连接完成后,对幻灯片视图控制器类本身进行代码修改,以加载图像。清单 3 显示了该类别的完整的第一版。
清单 3. SlideshowViewController.m
#import "slideshowViewController.h" @implementation slideshowViewController - (void)didReceiveMemoryWarning { [super didReceiveMemoryWarning]; } #pragma mark - View lifecycle - (void)viewDidLoad { [super viewDidLoad]; NSURL *imageURL = [NSURL URLWithString:@"http://localhost/photos/CRW_0675.jpg"]; NSData *imageData = [NSData dataWithContentsOfURL:imageURL]; UIImage *image = [UIImage imageWithData:imageData]; [imgView setImage:image]; } - (void)viewDidUnload { [super viewDidUnload]; } - (BOOL)shouldAutorotateToInterfaceOrientation: (UIInterfaceOrientation)interfaceOrientation { return YES; } @end |
slideshowViewController
类中的重要工作是以viewDidLoad
方法完成的,现在:
- 加载来自 URL的数据。
- 将数据转换成图像。
- 在图像视图上使用
setImage
方法显示该图像。
此时,您应该运行该应用程序来测试图像是否会出现。您会看到与图 7 相似的内容,该图显示了 iPad 模拟器中显示图像。
图 7. 来自服务器的第一个图像
如果您没有看到图像,问题很可能是因为 setImage
方法调用 imgView
。验证 UIImageView
对象是否正确地连接到 imgView
变量。如果在此之前,应用程序发生了故障,那么您的 URL 可能不正确,或者服务器上的某些项目不正确。
现在您有方法显示 iPad 上的图像,下一步是加载 XML 获得要显示的所有图像的列表。iOS 框架拥有内置的 XML 解析器,因此,您只需要创建解析器对象并聆听各种标记的回调。
通过 NSXMLParserDelegate
接口扩展类本身,这会告知 iOS 框架该类能够从 XML 解析器接收回调。您还需要添加一个称为photos
的阵列,该阵列保存了从 XML 中提取的 URL 列表。清单 4 显示了更新情况。
清单 4. 附带照片的 SlideshowViewController.h
#import <UIKit/UIKit.h> @interface slideshowViewController : UIViewController<NSXMLParserDelegate> { IBOutlet UIImageView *imgView; NSMutableArray *photos; } @end |
如果编写更多的 iOS 应用程序,您将发现您会使用越来越多的指令来连接到各种 API。还存在针对表格的回调、UI 元素、GPS 回调等。您甚至能够为您自己的库创建自己的自定义接口。
要使用 XML 解析器,请扩展视图控制器类,如 清单 5 所示。
清单 5. 附带照片的 SlideshowViewController.m - (void)viewDidLoad { [super viewDidLoad]; photos = [[NSMutableArray alloc] init]; NSXMLParser *photoParser = [[[NSXMLParser alloc] initWithContentsOfURL: [NSURL URLWithString:@"http://localhost/photos/index.xml"]] autorelease]; [photoParser setDelegate:self]; [photoParser parse]; NSURL *imageURL = [NSURL URLWithString:[photos objectAtIndex:0]]; NSData *imageData = [NSData dataWithContentsOfURL:imageURL]; UIImage *image = [UIImage imageWithData:imageData]; [imgView setImage:image]; } - (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict { if ( [elementName isEqualToString:@"photo"]) { [photos addObject:[attributeDict objectForKey:@"url"]]; } } |
该类以 viewDidLoad
方法创建了一个解析器,并使它请求并解析来自服务器的 XML。它还为解析器设置回指令,从而得到回调。
在该示例中,您想要监听每当遇到标记时都会触发的 didStartElement
回调。didStartElement
函数查看标记名称是否为照片标记。如果是的话,didStartElement
将url
属性的值添加到照片阵列。
在完成了照片阵列后,viewDidLoad
方法会继续并将图像设置为阵列中的第一个图像。
运行该应用程序来测试您的进度。您应看到在 XML 中指定的第一个图像出现在模拟器中。如果您没有看到第一个图像,那么服务器上的 XML 可能有问题。在didStartElement
方法中设置一个断点,查看它是否被调用。如果没有,那么您不会从服务器获取任何有效的 XML。
最后一步是使用照片阵列,使幻灯片成为动画。您将需要两个项目:
- 一个定时器
- 在幻灯片中保持您当前位置的变量
将这两个项目添加到类定义,如 清单 6 所示。
清单 6. SlideshowViewController.h 已完成
#import <UIKit/UIKit.h> @interface slideshowViewController : UIViewController<NSXMLParserDelegate> { IBOutlet UIImageView *imgView; NSMutableArray *photos; NSTimer *timer; int currentImage; } @end |
timer
是将以您指定的时间间隔触发事件的对象。currentImage
只是进入照片阵列的索引,您可使用它遍历所有的图像。
清单 7显示了幻灯片应用程序代码的最终版本。
清单 7. SlideshowViewController.m 已完成
#import "slideshowViewController.h" @implementation slideshowViewController - (void)didReceiveMemoryWarning { [super didReceiveMemoryWarning]; } #pragma mark - View lifecycle - (void)viewDidLoad { [super viewDidLoad]; photos = [[NSMutableArray alloc] init]; NSXMLParser *photoParser = [[[NSXMLParser alloc] initWithContentsOfURL:[NSURL URLWithString: @"http://localhost/photos/index.xml"]] autorelease]; [photoParser setDelegate:self]; [photoParser parse]; currentImage = 0; NSURL *imageURL = [NSURL URLWithString:[photos objectAtIndex:0]]; NSData *imageData = [NSData dataWithContentsOfURL:imageURL]; [imgView setImage:[UIImage imageWithData:imageData]]; timer = [NSTimer scheduledTimerWithTimeInterval: 5.0 target: self selector: @selector(handleTimer:) userInfo: nil repeats: YES]; } - (void) handleTimer: (NSTimer *) timer { currentImage++; if ( currentImage >= photos.count ) currentImage = 0; NSURL *imageURL = [NSURL URLWithString:[photos objectAtIndex:currentImage]]; NSData *imageData = [NSData dataWithContentsOfURL:imageURL]; [imgView setImage:[UIImage imageWithData:imageData]]; } - (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict { if ( [elementName isEqualToString:@"photo"]) { [photos addObject:[attributeDict objectForKey:@"url"]]; } } - (void)viewDidUnload { [super viewDidUnload]; } - (BOOL)shouldAutorotateToInterfaceOrientation: (UIInterfaceOrientation)interfaceOrientation { return YES; } @end |
清单 7中的这两个新元素是用viewDidLoad
方法创建定时器形成的,还添加了 handleTimer
方法,该方法在定时器被触发时会被调用。handleTimer
方法只递增currentImage
,如果到达阵列的末尾便会滚动索引。它还使用标准的图像抓取逻辑获得给定索引的图像,并显示该图像。
定时器有两种模式:它们可以一次性触发,也可以连续触发。在viewDidLoad
方法中,示例会重复指定 YES,这样 handleTimer
方法会在应用程序的整个生命周期一次又一次地被调用。
在本文中,您创建了一个基本的 iOS 应用程序。现在可以在多个不同的方向使用该应用程序。iOS CoreGraphics 框架提供了一套丰富的转换,您可以使用这些转换激活图像之间的变化。您可以在后端使用 PHP 动态地生成 XML。或者,您甚至可以使用 CoreAudio API 把一些音乐放置在整个幻灯片的背景中。