6.3 View之间的切换
在上面的练习中我们通过移动组件的位置和调整组件的大小来处理横向与纵向的界面布局。但是在界面中有很多组件的时候,对每个组件都进行这样的操作确实是一个麻烦的事情。下面我们看看处理屏幕旋转的第二种方法,在ViewController开始旋转之前进行view的切换。
实战:屏幕旋转时进行view的切换
打开Xcode,创建一个新的Xcode项目,选择View-based 应用程序模板,项目名称为AutoRotationSwap。
修改AutoRotationSwapViewController.h文件。
- #import <UIKit/UIKit.h>
- #define degreesToRadians(x) (M_PI * (x) / 180.0)
- @interface AutoRotationSwapViewController : UIViewController {
- UIView *landscape;
- UIView *portrait;
- UIButton *landscapeOneButton;
- UIButton *portraitOneButton;
- UIButton *landscapeTwoButton;
- UIButton *portraitTwoButton;
- }
- @property (nonatomic, retain) IBOutlet UIView *landscape;
- @property (nonatomic, retain) IBOutlet UIView *protrait;
- @property (nonatomic, retain) IBOutlet UIButton *landscapeOneButton;
- @property (nonatomic, retain) IBOutlet UIButton *portraitOneButton;
- @property (nonatomic, retain) IBOutlet UIButton *landscapeTwoButton;
- @property (nonatomic, retain) IBOutlet UIButton *portraitTwoButton;
- @end
在Interface Builder中编辑AutoRotationSwapViewController.xib文件,选中AutoRotation SwapViewController.xib窗口中的view,按Delete键将其删除。从Library窗口中拖曳两个View到该窗口中。
选中其中的一个view,然后在名称上面再单击鼠标,将其名称修改为Portrait,用同样方法将另一个view的名称修改为Landscape,如图6-11所示。
![]() |
图6-11 删除原有的view,添加两个新的view并且重新命名 |
按鼠标右键拖曳File's Owner图标到Portrait图标上,在弹出的Outlets快捷菜单上选择portrait。再拖曳File's Owner图标到Landscape上,和landscape建立Outlet关联,如图6-12所示。
![]() |
图6-12 将Portrait和Landscape建立Outlet关联 |
再次用鼠标右键拖曳File's Owner图标到Portrait上面,在Outlets快捷菜单上选择view,表明ViewController首先载入的是此view,也就是纵向模式的这个view,如图6-13所示。
![]() |
图6-13 将view与Portrait建立关联 |
双击Landscape图标,通过快捷键Command+3调整此view的大小,宽度设置为480,高度为300。从Library中拖曳两个Button组件,并修改其Title分别为One和Two,如图6-14所示。
![]() |
(点击查看大图)图6-14 设置Landscape界面 |
通过File's Owner图标设置One和Two两个按钮的Outlet,分别关联landscapeOneButton和landscapeTwoButton。
双击portrait图标,拖曳两个Button到该view中,Title也分别设置为一和二,同样进行Outlet关联,分别为portraitOneButton和portraitTwoButton,如图6-15所示。
![]() |
(点击查看大图)图6-15 设置portrait界面 |
关闭Interface Builder返回到Xcode。在AutoRotationSwapViewController.m文件中进行如下修改。
- #import "AutoRotationSwapViewController.h"
- @implementation AutoRotationSwapViewController
- @synthesize landscape;
- @synthesize portrait;
- @synthesize landscapeOneButton;
- @synthesize portraitOneButton;
- @synthesize landscapeTwoButton;
- @synthesize portraitTwoButton;
- - (BOOL)shouldAutorotateToInterfaceOrientation:
- (UIInterfaceOrientation)interfaceOrientation {
- return YES;
- }
- - (void)willAnimateRotationToInterfaceOrientation:
- (UIInterfaceOrientation) interfaceOrientation
- duration:(NSTimeInterval)duration {
- if (interfaceOrientation == UIInterfaceOrientationPortrait) {
- selfself.view = self.portrait;
- self.view.transform = CGAffineTransformIdentity;
- self.view.transform = CGAffine
TransformMakeRotation(degreesToRadians(0)); - self.view.bounds = CGRectMake(0.0, 0.0, 320.0, 460.0);
- } else if (interfaceOrientation ==
UIInterfaceOrientationLandscapeLeft) { - selfself.view = self.landscape;
- self.view.transform = CGAffineTransformIdentity;
- self.view.transform =
CGAffineTransformMakeRotation(degreesToRadians(-90)); - self.view.bounds = CGRectMake(0.0, 0.0, 480.0, 300.0);
- } else if (interfaceOrientation ==
UIInterfaceOrientationPortraitUpsideDown) { - selfself.view = self.portrait;
- self.view.transform = CGAffineTransformIdentity;
- self.view.transform =
CGAffineTransformMakeRotation(degreesToRadians(180)); - self.view.bounds = CGRectMake(0.0, 0.0, 320.0, 460.0);
- } else if (interfaceOrientation ==
UIInterfaceOrientationLandscapeRight) { - selfself.view = self.landscape;
- self.view.transform = CGAffineTransformIdentity;
- self.view.transform =
CGAffineTransformMakeRotation(degreesToRadians(90)); - self.view.bounds = CGRectMake(0.0, 0.0, 480.0, 300.0);
- }
- }
- - (void)viewDidUnload {
- // Release any retained subviews of the main view.
- // e.g. self.myOutlet = nil;
- self.portrait = nil;
- self.landscape = nil;
- self.portraitOneButton = nil;
- self.portraitTwoButton = nil;
- self.landscapeOneButton = nil;
- self.landscapeTwoButton = nil;
- [super viewDidUnload];
- }
- - (void)dealloc {
- [portrait release];
- [landscape release];
- [portraitOneButton release];
- [portraitTwoButton release];
- [landscapeOneButton release];
- [landscapeTwoButton release];
- [super dealloc];
- }
执行Build and Run命令。在模拟器中纵向模式和横向模式效果如图6-16所示。
![]() |
(点击查看大图)图6-16 模拟器中的运行效果 |
在这一部分的练习中我们需要两个不同的view以适应不同的显示方向,所以首先在AutoRotationSwapViewController.h文件中定义两个UIView,以及相应的4个UIButton,同时我们还定义了一个宏:
- #define degreesToRadians(x) (M_PI * (x) / 180.0)
它帮助我们把角度值转换为弧度值,方便我们在AutoRotationSwapViewController.m文件中进行view的手工旋转。当然手工旋转view时可以直接使用弧度,但是大多数人对于弧度的表象远不如角度直观,所以我们添加了这样的一个宏。
在Interface Builder中我们向AutoRotationSwapViewController.xib里面添加两个新的view。虽然原始的xib中已经含有一个view,但是这个view的大小是不可变的,如图6-17所示。size属性的高度和宽度均为灰色,根本无法修改。所以我们在AutoRotationSwapViewController.xib窗口中删除默认的这个view后再加入两个全新的view。
![]() |
图6-17 添加两个新的view |
需要我们注意的是,除了对新添加的两个view分别和portrait与landscape建立Outlet关联以外,还要将AutoRotationSwapViewController.xib自身的view与portrait再次建立Outlet关联,使得该view在启动时就被显示出来。
接下来我们将Landscape view调整为480×300,因为状态条占据20的高,所以这个view的高度就为300。
对AutoRotationSwapViewController.xib的设置完成以后,我们再次返回到Xcode。
首先修改shouldAutorotateToInterfaceOrientation方法,使其返回值为YES,也就意味着该ViewController支持所有方向的屏幕旋转。
然后,增加willAnimateRotationToInterfaceOrientation:duration:方法,这个方法来自于继承的UIViewController类,我们在当前类中重写该方法,并在view开始旋转之前调用这个方法。在这个方法中我们根据参数传递进来的设备旋转的方向设置当前的view是portrait还是landscape。调用了CGAffineTransformMakeRotation方法,CGAffineTransformMakeRotation方法是Core Graphics框架的一部分,它创建一个旋转变形(Rotation Transformation)。变形(Transformation)是通过数学方式表明一个对象的大小、位置和角度的改变。一般来说,iOS在设备被旋转的时候会自动设置变形的值,但是我们在设备旋转的时候更改了当前的view,为了不让这个操作对iOS的自动变形设置产生混乱,我们通过CGAffineTransformMakeRotation方法手动对交换后的view进行旋转变形。