从零开始学iOS开发(九):Swapping Views


  这篇的内容是切换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

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的类型,

成“OutletCollection”,并命名为foos,单击Connect完成添加。


  添加完成后,切换到Landscape View,选中Foo按钮,control + 鼠标拖动到已添加的Outlet Collection foos上,这样Landscape View中Foo按钮也加入到了foos集合中。

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

1 #import <UIKit/UIKit.h>
2 
3 @interface BIDViewController : UIViewController
4 @property (strong, nonatomic) IBOutlet UIView *portrait;
5 @property (strong, nonatomic) IBOutlet UIView *landscape;
6 @property (strong, nonatomic) IBOutletCollection(UIButton) NSArray *foos;
7 @property (strong, nonatomic) IBOutletCollection(UIButton) NSArray *bars;
8 
9 @end

6)添加Action

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

1 @interface BIDViewController : UIViewController
2 @property (strong, nonatomic) IBOutlet UIView *portrait;
3 @property (strong, nonatomic) IBOutlet UIView *landscape;
4 @property (strong, nonatomic) IBOutletCollection(UIButton) NSArray *foos;
5 @property (strong, nonatomic) IBOutletCollection(UIButton) NSArray *bars;
6 
7 - (IBAction)buttonTaped:(id)sender;
8 @end

7)实现View的切换

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

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

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

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

 1 - (void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration {
 2     
 3     if(toInterfaceOrientation == UIInterfaceOrientationPortrait) {
 4         self.view = self.portrait;
 5         self.view.transform = CGAffineTransformIdentity;
 6         self.view.transform = CGAffineTransformMakeRotation(degreesToRadians(0));
 7         self.view.bounds = CGRectMake(0.0, 0.0, 320.0, 460.0);
 8     }
 9     else if(toInterfaceOrientation == UIInterfaceOrientationLandscapeLeft) {
10         self.view = self.landscape;
11         self.view.transform = CGAffineTransformIdentity;
12         self.view.transform = CGAffineTransformMakeRotation(degreesToRadians(-90));
13         self.view.bounds = CGRectMake(0.0, 0.0, 480.0, 300.0);
14     }
15     else if(toInterfaceOrientation == UIInterfaceOrientationLandscapeRight) {
16         self.view = self.landscape;
17         self.view.transform = CGAffineTransformIdentity;
18         self.view.transform = CGAffineTransformMakeRotation(degreesToRadians(90));
19         self.view.bounds = CGRectMake(0.0, 0.0, 480.0, 300.0);
20     }
21 }

  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,添加代码如下

 1 - (IBAction)buttonTaped:(id)sender {
 2     NSString *message = nil;
 3     
 4     if([self.foos containsObject:sender])
 5         message = @"Foo button pressed";
 6     else
 7         message = @"Bar button pressed";
 8     
 9     UIAlertView *alert = [[UIAlertView alloc] initWithTitle:message
10                                                     message:nil
11                                                    delegate:nil
12                                           cancelButtonTitle:@"ok"
13                                           otherButtonTitles:nil];
14     [alert show];
15 }

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

  if([self.fooscontainsObject: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方法改成如下样子

 1 - (IBAction)buttonTaped:(id)sender {
 2     /*
 3     NSString *message = nil;
 4     
 5     if([self.foos containsObject:sender])
 6         message = @"Foo button pressed";
 7     else
 8         message = @"Bar button pressed";
 9     
10     UIAlertView *alert = [[UIAlertView alloc] initWithTitle:message
11                                                     message:nil
12                                                    delegate:nil
13                                           cancelButtonTitle:@"ok"
14                                           otherButtonTitles:nil];
15     [alert show];
16     */
17     
18     if([self.foos containsObject:sender]) {
19         for (UIButton *oneFoo in foos) {
20             oneFoo.hidden = YES;
21         }
22     }
23     else {
24         for (UIButton *oneBar in bars) {
25             oneBar.hidden = YES;
26         }
27     }
28         
29 }

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

  编译运行,点击bar按钮,bar按钮被隐藏

  旋转iphone,另一个View中的bar按钮也被隐藏了

Swap All


优质内容筛选与推荐>>
1、也说说Sybase ASE数据库的基本使用
2、[转]JetBrains IntelliJ IDEA 13 Keygen (Java Source Code)
3、Adroid学习之SD卡的操作(1)
4、物资管理系统
5、利用规则引擎打造轻量级的面向服务编程模式


长按二维码向我转账

受苹果公司新规定影响,微信 iOS 版的赞赏功能被关闭,可通过二维码转账支持公众号。

    阅读
    好看
    已推荐到看一看
    你的朋友可以在“发现”-“看一看”看到你认为好看的文章。
    已取消,“好看”想法已同步删除
    已推荐到看一看 和朋友分享想法
    最多200字,当前共 发送

    已发送

    朋友将在看一看看到

    确定
    分享你的想法...
    取消

    分享想法到看一看

    确定
    最多200字,当前共

    发送中

    网络异常,请稍后重试

    微信扫一扫
    关注该公众号





    联系我们

    欢迎来到TinyMind。

    关于TinyMind的内容或商务合作、网站建议,举报不良信息等均可联系我们。

    TinyMind客服邮箱:support@tinymind.net.cn