从零开始学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按钮被点击了

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 *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按钮也被隐藏了

Swap All

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

时间: 2024-12-26 08:57:01

从零开始学ios开发(九):Swapping Views的相关文章

从零开始学ios开发(十五):Navigation Controllers and Table Views(中)

这篇内容我们继续上一篇的例子接着做下去,为其再添加3个table view的例子,有了之前的基础,学习下面的例子会变得很简单,很多东西都是举一反三,稍稍有些不同的内容,好了,闲话少说,开始这次的学习. 如果没有上一篇的代码,可以从这里下载Nav_1 1)第三个subtableview:Controls on Table Rows这个例子,我们将为每个table view的每一行添加一个按钮,这个按钮将放在accessory icon的位置(之前我们使用过accessoryType,其实这也是一个

从零开始学ios开发(十四):Navigation Controllers and Table Views(上)

这一篇我们将学习一个新的控件Navigation Controller,很多时候Navigation Controller是和Table View紧密结合在一起的,因此在学习Navigation Controller的同时,我们还将继续学习Table View其他一些特性,毕竟Navigation Controller还是相对来说毕竟简单的,没有什么太大的花头,它的主要作用就是一个view的切换,切来切去,而Table View的花头就比较多了,这次我们将这2个控件结合在一起进行学习. 再多说一

从零开始学ios开发(十二):Table Views(中)UITableViewCell定制

我们继续学习Table View的内容,这次主要是针对UITableViewCell,在前一篇的例子中我们已经使用过UITableViewCell,一个默认的UITableViewCell包含imageView.textLabel.detailTextLabel等属性,但是很多时候这些默认的属性并不能满足需要,其实更多的时候我们想自己制定UITableViewCell的内容,这篇学习的就是制定自己的UITableViewCell. UITableViewCell继承自UIView,因此它可以加载

从零开始学ios开发(十三):Table Views(下)Grouped and Indexed Sections

在前面2篇关于Table View的介绍中,我们使用的Style都是Plain,没有分组,没有index,这次学习的Table View和iphone中的通讯录很像,有一个个以字符为分割的组,最右边有一列小字符作为index,最顶端有一个搜索栏可以进行搜索,好了,下面开始这次的学习. 1)创建一个新的项目,template选择Single View Application,命名为Sections 2)添加Table View,连接delegate和data source到File's Owner

从零开始学ios开发(十九):Application Settings and User Defaults(上)

在iphone和ipad中,有一个东西大家一定很熟悉,那个东西就是Settings. 这次要学习的东西说白了很简单,就是学习如何在Settings中对一个app的某些属性进行设置,反过来,在app中更改了一些属性值,也会反应到Settings中,这个功能很常用,实现起来也相对简单,但是内容还是比较多的. 首先还是对Settings进行一个简单的说明,虽然我们经常打开Settings,但是很少对Settings进行过仔细的研究,不过作为一名ios的开发人员,有这个必要对Settings进行一番探索

从零开始学ios开发(十二):Table Views(上)

这次学习的控件非常重要且非常强大,是ios应用中使用率非常高的一个控件,可以说几乎每个app都会使用到它,它就是功能异常强大的Table Views.可以打开你的iphone中的phone.Messages.Contacts.Mail.Settings等等等等,这些都用到了Table Views. 在Table Views中,Table是用来显示一系列数据的,每条数据占用且只占用一行(一个table cell),在ios中没有规定table到底可以容纳多少行数据,也就是说,只要内存足够多,tab

从零开始学ios开发(十):Multiview Applications(多个xib之前的切换)

这篇学习的主要内容是Multiview,在我们学习iphone旋转的时候,介绍过多个view的使用方法,不过这里的view和旋转屏幕中所指的多个view是不同的,旋转屏幕中涉及到的多个view是在一个xib文件中的,而我们这里所指的mulitview,则是指多个xib,在多个xib中进行view的切换,也就是从一个xib切换到另一个xib,而每个xib中只有一个view. 另外的一个不同点体现在创建项目的时候,到目前为止,我们创建的所有项目的template都是single view,这次创建的

从零开始学ios开发(八):Autorotation and Autosizing

不好意思,这一篇间隔的时间有点长,最近实在是事情太多,耽搁了,好了,长话短说,下面继续学习ios. 这次学习的内容是Autorotation和Autosizing,Autorotation就是屏幕内容自动旋转,因为iphone有重力感应系统(陀螺仪???),屏幕的内容会随着用户手握iphone的方式(竖着握Portrait.横着握Landscape)而改变,这个相信大家都已经有所体会,Autosizing是指当iphone的屏幕旋转后,屏幕里面控件的大小和位置也会自动改变.好了,下面跟着例子继续

从零开始学ios开发(六):IOS控件(3),Segmented Control、Switch

这次的学习还是基于上一个项目继续进行(你也可以新建一个项目)学习Segmented Control和Switch. Segmented Control Switch Segmented Control和Switch的主要区别在于Segmented Control可以有多个值进行选择,而Switch只有2个值. 1)添加Segmented Control从object library中拖一个Segmented Control到iphone界面上然后调整Segmented Control位置以及它的