开发者分步演示如何将iPhone应用移植至iPad平台

我最近刚将自己的几款应用从iPhone平台移植到iPad平台,因此想要在此分享自己的几点经验收获。

  在本指南中,你将动手实践如何将应用从iPhone移至iPad平台。文章将谈论一个呈现系列棋盘游戏,供大家进行评级的简单应用,然后我们会将其移至iPad平台。

  在此过程中,我们将谈及如何测试内容所搭载的设备,以及如何自动调整大小和方向,如何针对iPad制作不同版本的XIB,还有就是如何及何时运用新iPad元素。

  你将从本指南中有所收获,在着手移植工作前学习如何运用UISplitView和UIPopoverController,但这并非硬性要求。

PortFinalSmall from raywenderlich.com

  将要移植的iPhone应用

  我们即将移植的是名为“PortMe”的简单应用,其包含些许体现在许多iPhone应用中的元素(游戏邦注:表格视图、标准视图控制器及编辑性能)。

Before from raywenderlich.com

  所以要攫取即将移植的iPhone应用副本,然后进行查看。

  你会看到其中包含3个视图控制器。第一个是系列棋盘游戏的表格视图。第二个是包含XIB的视图控制器,旨在呈现棋盘游戏的具体细节内容。第三个是供玩家评论棋盘游戏的表格视图。

  查看应用,确保自己熟悉把握其结构。完成这些之后,你就能够着手移植工作。

  基于iPad升级目标内容

  将应用从iPhone移植到iPad平台的初始步骤相当简单。只需扩展Target,选择“PortMe”,然后点击“ProjectUpgrade Current Target for iPad”。

UpgradeCurrentTarget from raywenderlich.com

  这里你有两个选择——一个是通用应用,或是两个针对特定设备的应用。若你选择“一个通用应用”(One universal application),那么你就能够制作出用户只需购买一次,能够同时于iPhone或iPad运行的应用。若你希望用户单独购买应用,那么你多半会选择“两个瞄准特定设备的应用”(Two device-specific applications)。

  这里,我们要制作的是一款通用应用,所以请点击这一选项,选中OK。

  下面就来看看这所带来的结果。首先就是在“Resources-iPad”文件夹中创建名为“MainWindow-iPad.xib”的新文件。

  打开文件后,双击窗口,你将看到一个iPad尺寸的窗口。这一XIB还包含出现在原始XIB中的对象——以PortMeGameListController作为基础视图控制器的导航控制器。

MainWindowiPad from raywenderlich.com

  再来就是将项目同3.2 SDK连接起来。你会发现进行3.2 SDK编辑不再是个选项:

Link 3.2 SDK from raywenderlich.com

  这点也体现在Target Info中;它将Base SDK调整成“iPhone Device 3.2”,将Targeted Device Family变更成iPhone/iPad:

TargetInfo from raywenderlich.com

  现在来看看应用的具体形态。确保选中“Simulator–3.2”,然后运行吸盘。你会发现第一个屏幕看起来不会很糟,因为表格视图自动调整屏幕的尺寸,但我们的第二个屏幕就没有进展得这么顺利。

PortMe1 from raywenderlich.com

  所以我们从iPad移植过程中学到第一课——这不像选择“Upgrade Current Target for iPad”(基于iPad升级当前目标内容)选项那么简单。现在我们进入最有趣的部分——重新调整应用,以配合更大尺寸规格和新标准/新机会。

  下面就来修复这一混乱视图。

  自动调整尺寸

  开始创建这一试样项目时,我将若干UI元素拖到视图中,完全没有留意自动调整尺寸属性——在没有循环支持的前提下制作iPhone应用属于常见情况。

  但现在我们希望应用支持大、小屏幕规格,且支持循环模式,那么自动调整尺寸就变得特别重要。通过自动调整尺寸,我们可以告知各UI元素当母视图发生变化时要如何做出反应。

  查看这一操作过程最简单的方式是亲自进行试验。打开PortMeGameDetailsController.xib,双击视图。

  关于顶部的两个标签,我们希望其宽度会随视图宽度的扩大而扩大。所以选择这两个标签,然后切换到检验器中的第三个标签。在自动调整尺寸版块下方,点击浅红色区域,直到其呈现如下画面:

Autosizing1 from raywenderlich.com

  右侧动画向你呈现选择的最终反应;在这种情况下,这意味着标签的宽度应随视图的扩大而扩大,它们应同上、左、右边界保持当前距离。

  现在就来着手剩下的内容。按照如下方式设置UIImageView:

Autosizing2 from raywenderlich.com

  这意味着UIImageView的宽度和高度应随视图的扩展而扩展,稳固附着在视图边缘。

  按照如下方式设置文本视图:

Autosizing3 from raywenderlich.com

  按照如下方式设置标签:

Autosizing4 from raywenderlich.com

  最后是将按键设置成如下样式:

Autosizing5 from raywenderlich.com

  下面就来看看最终结果!确保保存XIB,然后编译和运行项目,你将看到一个完善后的新视图:

AutoresizingResult from raywenderlich.com

  这无疑有所改善!

  但这里依然存在一个重要问题:若你希望模拟器的循环属性是“HardwareRotate Left”——iPad旋转,但应用没有旋转!由于支持所有情况是iPad应用的必要条件,因此这意味着我们需要在此形成即刻抵制。

  幸运的是,由于我们正确设定视图的自动调整尺寸属性(游戏邦注:还有UITableViewController已支持循环模式),我们可以通过几行代码进行修复。

  将下述代码添加至PortMeGameListController.m、PortMeGameDetailsController.m和PortMeGameRatingController.m末尾:

- (BOOL)shouldAutorotateToInterfaceOrientation: (UIInterfaceOrientation)toInterfaceOrientation { return YES;}

  编译和运行应用,现在你应该能够将手机旋转至任何方向,且各元素能够正确移动:

OrientationResult from raywenderlich.com

  到目前为止一切进展顺利!但此时我们的主要问题是,我们依然基于iPhone模式进行思考。iPad存在广阔的屏幕空间,我们希望充分利用这些元素,而不是迫使玩家深入钻研各种层级。

  这就是UISplitViewController和UIPopoverController的用途所在。所以现在就来看看我们如何在应用中发挥这些工具——同时重复利用我们既有的视图控制器。

  整合UISplitViewController

  UISplitViewControllers旨在让你在左侧浏览条目,然后在右侧查看条目细节。

  这非常适合我们的应用!我们可以将棋盘游戏列表放在左侧,将棋盘游戏细节内容放在右侧。

  所以我们将接着把UISplitViewController植入我们的项目中。打开MainWindow-iPad.xib,将Split View Controller拖到窗口中,取消原始Navigation Controller。

  扩展Split View Controller树形图,直到发现Table View Controller。锁定Inspector的第4个标签,将Class设置成PortMeGameListController。

  现在我们需要设置右侧内容。不妨先思考片刻。当用户点击“Rate This”时,我们通常会将另一视图控制器推向堆栈中。这意味着右侧视图控制器也必须属于UINavigationController类。

  所以将View Controller之上的Navigation Controller拖到右侧,深入其中,将基础视图控制器设置成“PortMeGameDetailsController”。完成这些操作后,获得的最终结果如下:

SplitView 2 from raywenderlich.com

  现在我们需要将此同代码连接起来。目前Application Delegate把navController属性添加为主窗口的子视图。但在iPad中,我们希望其把分离视图控制器添加到窗口中。

  这意味着我们需要分离视图控制器输出端口。我们也许倾向将其称作标准模式——但记住这个应用需要同时运作于iPhone(运行iPhone OS 3.0-3.1.3)和iPad(运行iPhone OS 3.2)平台。顺便说下,iPhone OS 3.2只针对iPad平台。

  所以这意味着原始OS版本将不具备UISplitViewController类,试图声明这一类型的变量会带来问题。因此,我们需要更加谨慎地运用这些类型,通过运行时间检查新符号文件。

  查看如何进行操作的最简单方式就是进行尝试。打开PortMeAppDelegate.h,添加下述代码:

  // In the class interface
id _splitViewController;

  // Afterwards
@property (nonatomic, retain) IBOutlet id splitViewController;

  这里我们将SplitViewController标注成普通ID,所以我们可以在运行时间加载各类别,避免3.0 OS存在的问题。

  然后将下述内容添加至PortMeAppDelegate.m:

  // In synthesize section
@synthesize splitViewController = _splitViewController;

  // In didFinishLaunchingWithOptions, replace window addSubview line with:
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
UIView *view = [_splitViewController view];
[window addSubview:view];
} else {
[window addSubview:_navController.view];
}

  // In dealloc
self.splitViewController = nil;

  第一行旨在测试代码是否在iPad上运行。若它在iPad上运行,我们就无法将分离视图控制器添加成窗口的子视图。

  由于我们将分离视图保存成普通对象(游戏邦注:而不是UISplitViewController类),因此我们需要通过向其发送信息获得视图。

  这就是有关代码部分的内容。最后就是回到MainWindow-iPad.xib,将其从“Port Me App Delegate”拖动到“Split View Controller”,然后同“splitViewController”输出口连接起来,然再从“Port Me App Delegate”拖到“Port Me Game List Controller”,将其同“gameListController”输出口连接起来。

  记得保存XIB,然后编译和运行应用,接着切换到横屏模式。游戏列表会在左侧呈现OK标识,但当你点击游戏时,它就会出现在同个浏览控制器中,而非右侧边:

SplitView 3 from raywenderlich.com

  所以现在就来着手下部分内容!

  连接细节视图

  就如在UISplitView指南中提到的,连接分离视图左右侧的方式多种多样,但表现最为突出的一个方式是授权(delegation)。

  所以我们将遵循在上个指南中采用的方式,设定“选定游戏”的协议,其中我们通过落实细节视图对视图进行更新。

  事实上,这是个不错的想法,这里你可以尝试独立进行这一操作,务必记住操作流程。若你成功独立将此落实到位,那么不妨跳到下个版块。否则,你需要继续按步操作。

  若你选择继续按步操作,转移到FileNew,选择Objective-C类,确保“Subclass of”的状态是“NSObject”,点击“Next”。将文件命做“Next”,然后点击“Finish”。

  在PortMeGameDetailsController.h中做出如下调整:

  // Add UISplitViewControllerDelegate to the list of protocols
@interface PortMeGameDetailsController : UIViewController
{

  // Inside the class definition
id _popover;

  // In the property section
@property (nonatomic, retain) id popover;

  这和我们在上个指南中所进行的操作类似,不同之处在于我们将UIPopoverController标识作通用对象,旨在避开3.0-3.1.3 OS所存在的问题。

  在PortMeGameDetailsController.m添加下述内容:

  // In synthesize section
@synthesize popover = _popover;

  // In dealloc and viewDidUnload
self.popover = nil;

  // In gameSelectionChanged
if (_popover != nil) {
[_popover dismissPopoverAnimated:YES];
}

  // New functions
- (void)splitViewController: (UISplitViewController*)svc
willHideViewController:(UIViewController *)aViewController
withBarButtonItem:(UIBarButtonItem*)barButtonItem
forPopoverController: (UIPopoverController*)pc {
barButtonItem.title = @”Sidebar”;

  UINavigationItem *navItem = [self navigationItem];
[navItem setLeftBarButtonItem:barButtonItem animated:YES];

  self.popover = pc;
}

  - (void)splitViewController: (UISplitViewController*)svc
willShowViewController:(UIViewController *)aViewController
invalidatingBarButtonItem:(UIBarButtonItem *)barButtonItem {

  UINavigationItem *navItem = [self navigationItem];
[navItem setLeftBarButtonItem:nil animated:YES];

  self.popover = nil;

  }

  然后将下述内容添加至PortMeGameListController.m中,旨在将Popover调小,而非采用屏幕的全高度:

  // In viewDidLoad
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
[self setContentSizeForViewInPopover:CGSizeMake(320.0, 300.0)];
}

  注意若是搭载iPad平台,我们只能运行这些内容,因为我们多半是采用3.0 OS版本。

  最后一点——回到MainWindow-iPad.xib,将其从“Split View Controller”拖至“Port Me Game Deetails Controller”,以将右侧的视图控制器设置成分离视图控制器授权类。

  编译和运行应用,若一切进展顺利,你应该在导航控制器上设置条目,这样你就能够点击呈现棋盘游戏列表。

SplitView 5 from raywenderlich.com

  运用UIPopoverController

  另一我们还过于基于iPhone模式进行思考的应用元素是速度按键。我们在此不应采用完全独立的屏幕,而是应该在iPad中运用UIPopoverController。

  这类似于我们在UIPopoverController中所采用的方式,但同时还是存在些许差异。

  将下述内容添加至PortMeGameDetailsController.h中:

  // Inside class declaration
id _ratingPopover;

  // In property section
@property (nonatomic, retain) id ratingPopover;

  同时注意这里采用普通对象,因为这是个通用运用。

  然后将下述内容添加至PortMeGameDetailsController.m中:

// In synthesize section@synthesize ratingPopover = _ratingPopover;// In dealloc AND viewDidUnloadself.ratingPopover = nil;// In rateTapped, replace pushViewController with the following:if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) { UIButton *button = (UIButton *)sender; if (_ratingPopover == nil) { Class classPopoverController = NSClassFromString(@"UIPopoverController"); if (classPopoverController) { self.ratingPopover = [[[classPopoverController alloc] initWithContentViewController:_ratingController] autorelease]; } } [_ratingPopover presentPopoverFromRect:button.frame inView:self.view permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES];} else { [self.navigationController pushViewController:_ratingController animated:YES];}

  这里我们再次根据是否运作于iPad进行切换,或呈现一个Popover,或和往常一样推到导航控制器中。

  但注意我们需要通过查找类名称创造Popover控制器,然后对其进行建构。这又是另一我们无法运用实际类名称的情况,因为我们也许搭载3.0设备。

  这里我们还通过不同的方式呈现popover控件,这让我们得以指定popover箭头将指向的矩形。

  接着切换到PortMeGameRatingController.m,添加如下内容:

  if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
[self setContentSizeForViewInPopover:CGSizeMake(320.0, 300.0)];
}

  编译和运行运用,若你选择游戏,点击速度后你将看到如下内容:

Rate from raywenderlich.com

  获得更优质的细节视图

  目前我们的端口进展得非常顺利,其表现更像是iPad风格。但我的细节视图依然可以进行更多雕琢。

  首先,背景图像主要针对iPhone平台,只是被扩大至更大的屏幕中。所以这在更高分辨率的情况下会显得有些粗糙。

  其次,我们可以更充分地利用强化版屏幕空间,主要通过扩大某些文本,或移动某些标签以更充分利用空间。

  当你开始做出众多调整以期出现预期视图时,你可以通过修改代码UI元素和接入UI_USER_INTERFACE_IDIOM()有计划地完成操作,但通常给iPad制作定制视图XIB要简单得多。

  所以现在就来动手尝试!打开PortMeGameDetailsController.xib,点击“FileCreate iPad Version Using Autosizing Masks”。这会生成一个Untitled XIB——在项目文件夹中保存XIB,将其命做“PortMeGameDetailsController-iPad.xib”。

  然后下载更高分辨率的背景图像副本,将UIImageView图像设置成“bg-iPad.jpg”。

  然后对界面进行完善。我建议将棋盘游戏类型移至游戏名称右侧,靠右对齐。确保适当调整自动调整尺寸掩码。此外,你还需要完善所有内容的字体大小。

  保存XIB。最后一个步骤就是确保加载iPad XIB。打开MainWindow-iPad.xib,选择“Port Me Game Details Controller”,切换到Inspector的首个标签。将NIB名称设置成“PortMeGameDetailsController-iPad.xib”。

  保存XIB,编译和运行项目。若一切进展顺利,你应该会看到如下新视图:

PortFinal from raywenderlich.com

  在iPhone上进行测试

  我们的应用在iPad看起来非常不错。下个步骤就是在iPhone上进行测试,确保所有内容都能够顺利运作。

  但我们还面临一个小问题。模拟器会默认直接发送到iPad模拟器(游戏邦注:而不是iPhone模拟器)。

  那么我们该怎么做?我采取的变通方法是,只在这一设备上进行测试。

  切换至“Device–3.2”,尝试编译和运行应用。我们收到如下错误消息:

iPhone3.2 from raywenderlich.com

  这没什么问题。我们可以通过设置Target Info解决这一问题。基本来说,虽然我们基于3.2 SDK进行编辑,但我们依然能够采用不同的SDK。

  这就是为什么我们谨慎对待所有运行检验——我们拥有3.2头文件,但这也许不是我们运行于设备上的实际代码。

  所以现在转移到Target Info,按照如下方式将iPhone OS Deployment Target设置成iPhone OS 3.0:

DeploymentTarget from raywenderlich.com

  再次运作内容,这次它们要能够合理地在iPhone上呈现——由于我们非常注重运行时期的检验,因此所有内容都正常运作。

Munchkin from raywenderlich.com

  总结

  以上就是本指南的全部内容,但在将内容提交至App Store平台前,你还需要完成如下操作:

  * 给iPad添加默认图片。你将需要常见的Default.jpg图片。但现在除此之外,iPhone尺寸的Default-Landscape.jpg和Default-Portrait.jpg图片也必不可少。这些图片的尺寸必须是1024×748(横屏)和 768×1004(竖屏)规格——基本上是屏幕尺寸扣除状态栏。

  * 将UISupportedInterfaceOrientations添加至你的info.plist中,同时插入应用支持的所有方向。

  * 在项目中添加72×72图标,主要运用于iPad平台,给你的info.plist创造新的核心CFBundleIconFiles,然后将两个图标的名称整组放入其中。OS将基于尺寸选择适当的图标。

  若干建议

  关于移植iPhone应用的一点建议是,注意不要同时显示两个popover控制器——这会令用户感到迷惑,若你这么做你的应用将遭到抵制。

  简单的解决办法就是在呈现另一popover控制器的时候关闭当前控制器。但有时候,你需要从分离视图左侧启动popover控制器(游戏邦注:因为左侧内容本身在竖屏模式中就是个popover)。

  关于这点,一个很好的解决办法就是在既有popover上调用setContentViewController,按照如下方式将其中内容替换成你将在新popover中填充的内容:

  [_sidebarPopoverController setContentViewController:
wasGonnaBeInMySecondPopoverViewController animated:YES];

  下步操作

  现在你已把握将iPhone应用移植至iPad平台的操作要点。

  这里我建议你阅读苹果的《iPad Programming Guide》,其中谈及众多我们前面谈到的内容,但同时还包含很多更丰富的信息。

  游戏邦注:原文发布于2010年5月24日,文章叙述以当时为背景

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值