从零开始学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 添加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> @interface BIDViewController : 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文件如下

@interface BIDViewController : 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);
}
else if(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);
}
else if(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";
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])
foos是Outlet Collection对象,是一个NSArray,里面有一个containObject方法,查看是否存在某个对象,上面的if语句的意思就是判断foos中是否包含触发buttonTappedAction的对象,即判断该Action是不是由2个Foo按钮触发的,如果不是,那么即使2个Bar按钮触发的。
9)编译运行 点击Foo,一个警告框弹出,告诉你Foo按钮被点击了
旋转iphone,点击Bar,同样警告框填出,告诉你Bar按钮被点击了
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 *oneFoo in foos) {
oneFoo.hidden = YES;
}
}
else {
for (UIButton *oneBar in bars) {
oneBar.hidden = YES;
}
} }

这里的for语句和C#中的foreach一样,都是遍历某个集合中的对象,首先判断是那个按钮触发了buttonTapped,然后就将该按钮所在的Outlet Collection中的所有对象隐藏,这样当然也就隐藏了另一个View中的按钮。
编译运行,点击bar按钮,bar按钮被隐藏 旋转iphone,另一个View中的bar按钮也被隐藏了
从零开始学ios开发(九):Swapping Views的更多相关文章
- 从零开始学 iOS 开发的15条建议
事情困难是事实,再困难的事还是要每天努力去做是更大的事实. 因为我是一路自学过来的,并且公认没什么天赋的前提下,进步得不算太慢,所以有很多打算从零开始的朋友会问我,该怎么学iOS开发.跟粉丝群的朋友交 ...
- 从零开始学IOS开发
从今天开始开一个坑,由于业务变动,要开始学习IOS开发进行IOS app开发,其实鄙人本身就是一只菜鸟加大学狗,有过两年的C#,ASP.NET MVC,微信公众平台开发经验,一只在继续努力着,从大三下 ...
- 从零开始学ios开发(三):第一个有交互的app
感谢大家的关注,也给我一份动力,让我继续前进.有了自己的家庭有了孩子,过着上有老下有小的生活,能够挤出点时间学习真的很难,每天弄好孩子睡觉已经是晚上10点左右了,然后再弄自己的事情,一转眼很快就到12 ...
- 从零开始学ios开发(一):准备起航
首先介绍一下自己的背景,本人09年研究生毕业,大学就不介绍了,反正是上海的一所211大学,学的是计算机科学与技术专业,学生时代,从事过ACM,没有什么太大的成就,中国的牛人是在太多,我的水平,估计连高 ...
- 从零开始学ios开发(十二):Table Views(上)
这次学习的控件非常重要且非常强大,是ios应用中使用率非常高的一个控件,可以说几乎每个app都会使用到它,它就是功能异常强大的Table Views.可以打开你的iphone中的phone.Messa ...
- 从零开始学ios开发(十九):Application Settings and User Defaults(上)
在iphone和ipad中,有一个东西大家一定很熟悉,那个东西就是Settings. 这次要学习的东西说白了很简单,就是学习如何在Settings中对一个app的某些属性进行设置,反过来,在app中更 ...
- 从零开始学ios开发(十三):Table Views(下)Grouped and Indexed Sections
在前面2篇关于Table View的介绍中,我们使用的Style都是Plain,没有分组,没有index,这次学习的Table View和iphone中的通讯录很像,有一个个以字符为分割的组,最右边有 ...
- 从零开始学ios开发(十六):Navigation Controllers and Table Views(下)
终于进行到下了,这是关于Navigation Controllers和Table Views的最后一个例子,稍微复杂了一点,但也仅仅是复杂而已,难度不大,我们开始吧. 如果没有上一篇的代码,可以从这里 ...
- 从零开始学ios开发(十五):Navigation Controllers and Table Views(中)
这篇内容我们继续上一篇的例子接着做下去,为其再添加3个table view的例子,有了之前的基础,学习下面的例子会变得很简单,很多东西都是举一反三,稍稍有些不同的内容,好了,闲话少说,开始这次的学习. ...
随机推荐
- 【思路,dp,BigInteger】ZOJ - 2598 Yet Another Digit
[redundant binary - 冗余二进制]:由0,1,2构成的二进制形式,基数还是2. 现给你一十进制数n,问其可转化成多少种冗余二进制形式. 首先要想到:2x = 2*2x-1 也就是说 ...
- Java计算机网络
计算机网络: 分布在不同的地域的计算机通过外接设备(路由器),实现共享和数据传输网络编程:网络编程主要是用来解决计算机和计算机之间的数据传输网络编程:不需要基于HTML就可以达到数据之间的传输,比如Q ...
- 50个常用的笔试、面试sql语句
50个常用的笔试.面试sql语句 2009-12-17 15:05 Student(S#,Sname,Sage,Ssex) 学生表Course(C#,Cname,T#) 课程表SC(S#,C#,s ...
- ocx在我indows7无法注册
公司今天用到一个 要用到ocx ,我调试好久都无法安装..... 后来在网上看到.原来是没有安装 VC Redist Installer(VC20052008201020122013)运行库合集 导 ...
- HTML5 Web SQL Database 数据库的使用方法【图文说明】
页面代码: <!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" c ...
- Hadoop集群错误
1.Hadoop集群所有的DataNode都启动不了解决办法 删除从节点.../usr/hadoop/tmp/dfs/ 下内容,再重新格式化namenode
- swift 闭包简写实际参数名$0、$1等理解
Swift 自动对行内闭包提供简写实际参数名,你也可以通过 $0 , $1 , $2 等名字来引用闭包的实际参数值. 如果你在闭包表达式中使用这些简写实际参数名,那么你可以在闭包的实际参数列表中忽略对 ...
- 第十一篇、微信小程序-input组件
主要属性: 效果图: ml: <!--style的优先级比class高会覆盖和class相同属性--> <!--头像--> <view style="displ ...
- Xcode - 方法注释插件
VVDocumenter-Xcode,自动生成注释,感觉比较方便的插件,分享下,应该很多人都知道= = 在 https://github.com/onevcat/VVDocumenter-Xcode ...
- 【学习笔记】【C语言】变量类型
根据变量的作用域,可以分为: 1.局部变量: 1> 定义:在函数(代码块)内部定义的变量(包括函数的形参) 2> 作用域:从定义变量的那一行开始,一直到代码块结束 3> 生命周期:从 ...