三十而立,從零開始學ios開發(九):Swapping Views

來源:互聯網
上載者:User

這篇的內容是切換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

 

 

 

 

 

 

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.