从零开始学ios开发(九):SwappingViews

王朝学院·作者佚名  2016-08-27
窄屏简体版  字體: 小  |  中  |  大  |  超大  

这篇的内容是切换Views,也是上一篇中提到的第三种当iphone发生旋转后改变布局的方式,先回顾一下上一篇中提到的三种方式 1、使用Autosizing 2、写code 3、重新弄个View,替换原先的View

切换View,顾名思义就是在两个不同的View中间进行切换,那么我们至少需要有2个View,一个View展现当竖着(Portrait)拿iphone时的界面,另一个View展现当横着(Landscape)拿iphone是的界面,当我们旋转iphone时,就在这2个View之间进行切换,给用户的感觉好像是用一个界面,其实我们是用2个View在进行替换。这样做的好处是不必处理复杂的控件重新布局问题,但是坏处是因为是2个不同的View,我们必须用2套控件,然后当一个控件进行改变时,在另一个View中的“相同”控件也应进行改变(例如在一个View中被隐藏了,那在另一个View中也应该被隐藏,因为是同一个界面嘛,这点很重要。)

好,废话少说,开始这篇的学习。

1)创建一个新的Single View项目,并命名为Swap

2)添加2个button 添加2个button,分别命名为Foo和Bar,长宽都为125,并像下图一样进行布局

3)添加另一个View(landscape view) 由于这个view是当前view(portrait view)的横向版本,其界面上的控件类型、个数、功能应该和PRotrait view一样,只是在布局上有些不同,因此最简便的方法便是先复制一个portrait view,然后对界面上的控件位置大小从新布局。

选中BIDViewController.xib,在xib的editor dock中找到View按住键盘上的option键,鼠标选中View并拖动鼠标,有一个绿色的加号出现,然后在View的同一层的下面放开鼠标,这样一个View就复制好了。(可能2个View重叠在一起,用鼠标移动上面的一个View,就会看到有2个View了)

在editor dock中选中新加的View,然后切换到Attributes inspector,找到Simulated Mertrics栏中的Orientation,将其属性改成Landscape,这样View就横过来了

但是另一个button不见了,因为button位置的原因,另一个button没有显示在View中,我们现在editor dock中选中看不见的那个button然后在Size inspector中将其起始点设成10,10看不见的那个button出现了重新对其布局

4)创建View的Outlet 因为我们要切换View,因此必须指定View的Outlet,这样我们就可以在代码中对View进行操作了,创建View的Outlet的方法和创建其他控件的Outlet的方法一样,按下control键,鼠标选中View,拖动到BIDViewController.h中释放,并命名即可。我们首先添加Portrait View的Outlet,命名为portrait添加Landscape View的Outlet,命名为landscape

5)创建button的Outlet Collection 和以往的略微有些不同,由于我们有两个View,但是这两个View中的按钮的作用是一样的,所以我们在创建按钮的Outlet时,可以使用Outlet集合,也就是Outlet Collection,Outlet Collection和Outlet的区别是,Outlet只能对应一个控件,Outlet Collection则可以对应多个控件,其实Outlet Collection就是一个Outlet的数组,里面可以存放任意多个Outlet,然后对其一一进行遍历。有了Outlet Collection后,我们在写Action的时候,只需要便利Outlet Collection,就可以其中包含的每个控件进行操作,会方便很多(否则你需要对每个控件声明一个Outlet,然后一一操作,这个不仅增加代码的复杂度,而且还很容易遗漏控件)。

添加Outlet Collection的方法和添加一般的Outlet方法一样,选中Portrait View中的button Foo,按住control键,鼠标拖动到BIDViewController.h,释放鼠标,在填出的框中改变类型Connection的类型,改成“Outlet Collection”,并命名为foos,单击Connect完成添加。添加完成后,切换到Landscape View,选中Foo按钮,control + 鼠标拖动到已添加的Outlet Collection foos上,这样Landscape View中Foo按钮也加入到了foos集合中。

使用同样的方法为两个Bar按钮添加Outlet Collection,并命名为bars。完成后的BIDViewController.h文件如下

#import <UIKit/UIKit.h>@interfaceBIDViewController : UIViewController

@property (strong, nonatomic) IBOutlet UIView *portrait;

@property (strong, nonatomic) IBOutlet UIView *landscape;

@property (strong, nonatomic) IBOutletCollection(UIButton) NSArray *foos;

@property (strong, nonatomic) IBOutletCollection(UIButton) NSArray *bars;@end

6)添加Action 为4个按钮添加Action buttonTapped,只要添加一个Action,其他几个按钮连接到这个Action即可,完整的BIDViewController.h文件如下

@interfaceBIDViewController : UIViewController

@property (strong, nonatomic) IBOutlet UIView *portrait;

@property (strong, nonatomic) IBOutlet UIView *landscape;

@property (strong, nonatomic) IBOutletCollection(UIButton) NSArray *foos;

@property (strong, nonatomic) IBOutletCollection(UIButton) NSArray *bars;

- (IBAction)buttonTaped:(id)sender;@end

7)实现View的切换 首先打开BIDViewController.m文件,然后添加一个宏定义在最上面(#import的下面)

#define degreesToRadians(x) (M_PI * (x) / 180.0)

这段宏的意思是将角度转成弧度,在iphone旋转时会用到,因为iphone的旋转角度是根据弧度来计算的,并不是角度,因此我们需要进行一个简单的转换。M_PI是一个预定义的值,就是3.14159265358979323846264338327950288

重载willAnimateRotationToInterfaceOrientation方法,添加在最后一个@synthesize的后面,如下

- (void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration {if(toInterfaceOrientation ==UIInterfaceOrientationPortrait) {

self.view =self.portrait;

self.view.transform =CGAffineTransformIdentity;

self.view.transform = CGAffineTransformMakeRotation(degreesToRadians(0));

self.view.bounds = CGRectMake(0.0,0.0,320.0,460.0);

}elseif(toInterfaceOrientation ==UIInterfaceOrientationLandscapeLeft) {

self.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);

}elseif(toInterfaceOrientation ==UIInterfaceOrientationLandscapeRight) {

self.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);

}

}

willAnimateRotationToInterfaceOrientation方法发生在旋转开始之后但是还未真正旋转之前,即旋转这个命令已经发出了,但是还没有开始旋转这个动作。

上面的这段code,有几个地方需要说明一下,我们拿一个if语句块进行说明

self.view=self.landscape; 根据iphone的选择方向,选择显示哪个View

self.view.transform= CGAffineTransformIdentity; 貌似是将view的旋转状态设置到默认状态,即初始化一下,这个不太了解,网上查到的说法是:线性代数里面讲的矩阵变换,这个是恒等变换


当 你改变一个view.transform属性的时候需要先恢复默认状态,然后再进行改变。

self.view.transform= CGAffineTransformMakeRotation(degreesToRadians(-90)); view的旋转弧度,将角度换算成弧度,然后进行旋转。

self.view.bounds =CGRectMake(0.0,0.0,480.0,300.0); CGRectMake在上一篇已经讲解过,即设置起始点和大小,bounds属性是第一次遇到,它和frame有些类似,但是不同的是,frame控件相对于父视图的位置,而bounds则是控件自身的位置,即没有相对于父视图的概念,因为我们旋转的都是view,因此其起始点自然都是(0.0 , 0.0)。

上面的这个旋转方法可以当做模板来使用,每当遇到切换view的时候,就可以直接复制粘贴该方法。

(额外说明一个问题,仔细观察上面的这个方法中CGRectMake中最后一个参数,最后一个参数是表面view的高度,但是是不是发现它少了20?原因是状态栏,iphone顶部的状态栏的高度是20,因此view的高度会减少20。)

8)实现buttonTappedAction 在BIDViewController.m中找到buttonTapped,添加代码如下

- (IBAction)buttonTaped:(id)sender {

NSString *message =nil;if([self.foos containsObject:sender])

message =@"Foo button pressed";elsemessage =@"Bar button pressed";

UIAlertView *alert =[[UIAlertView alloc] initWithTitle:message

message:nildelegate:nil

cancelButtonTitle:@"ok"otherButtonTitles:nil];

[alert show];

}

这段代码需要注意的就只有这一行

if([self.foos containsObject:sender])

foos是Outlet Collection对象,是一个NSArray,里面有一个containObject方法,查看是否存在某个对象,上面的if语句的意思就是判断foos中是否包含触发buttonTappedAction的对象,即判断该Action是不是由2个Foo按钮触发的,如果不是,那么即使2个Bar按钮触发的。

9)编译运行 点击Foo,一个警告框弹出,告诉你Foo按钮被点击了

旋转iphone,点击Bar,同样警告框填出,告诉你Bar按钮被点击了

Swap 1

10)更新buttonTapped 在开头的时候,我们说过,因为是2个View进行切换,因此在一个View中发生的变化也要体现在另一个View中,我们在这里举一个例子,当在一个View中点击一个按钮的时候,隐藏该按钮,那么在另一个View中也要把对应的按钮隐藏,将buttonTapped方法改成如下样子

- (IBAction)buttonTaped:(id)sender {/*NSString *message = nil;

if([self.foos containsObject:sender])

message = @"Foo button pressed";

else

message = @"Bar button pressed";

UIAlertView *alert = [[UIAlertView alloc] initWithTitle:message

message:nil

delegate:nil

cancelButtonTitle:@"ok"

otherButtonTitles:nil];

[alert show];*/if([self.foos containsObject:sender]) {for (UIButton *oneFooinfoos) {

oneFoo.hidden =YES;

}

}else{for (UIButton *oneBarinbars) {

oneBar.hidden =YES;

}

}

}

这里的for语句和C#中的foreach一样,都是遍历某个集合中的对象,首先判断是那个按钮触发了buttonTapped,然后就将该按钮所在的Outlet Collection中的所有对象隐藏,这样当然也就隐藏了另一个View中的按钮。

编译运行,点击bar按钮,bar按钮被隐藏旋转iphone,另一个View中的bar按钮也被隐藏了

Swap All

 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
 
© 2005- 王朝網路 版權所有 導航