IOS:屏幕旋轉與Transform


IOS:屏幕旋轉與Transform

 

  iTouch,iPhone,iPad設置都是支持旋轉的,如果我們的程序能夠根據不同的方向做出不同的布局,體驗會更好。

  如何設置程序支持旋轉呢,通常我們會在程序的info.plist中進行設置Supported interface orientations,添加我們程序要支持的方向,而且程序里面每個viewController也有方法

  supportedInterfaceOrientations(6.0及以后)

  shouldAutorotateToInterfaceOrientation(6.0之前的系統)

  通過viewController的這些方法,我們可以做到更小粒度的旋轉控制,如程序中僅僅允許個別界面旋轉。

 

一、屏幕旋轉背后到底做了什么呢?

  下面我們看個簡單的例子,用xcode新建一個默認的單視圖工程,然后在對應viewController的響應旋轉后的函數中輸出一下當前view的信息,代碼如下:

SvRotateViewController
//
// SvRotateViewController.m // SvRotateByTransform //
// Created by maple on 4/21/13. // Copyright (c) 2013 maple. All rights reserved. // 
#import "SvRotateViewController.h"

@interface SvRotateViewController () @end

@implementation SvRotateViewController - (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view, typically from a nib.
 self.view.backgroundColor = [UIColor grayColor]; } - (void)didReceiveMemoryWarning { [super didReceiveMemoryWarning]; // Dispose of any resources that can be recreated.
} - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation { return YES; } - (BOOL)shouldAutorotate { return YES; } - (NSUInteger)supportedInterfaceOrientations { return UIInterfaceOrientationMaskAll; } - (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration { NSLog(@"UIViewController will rotate to Orientation: %d", toInterfaceOrientation); } - (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation { NSLog(@"did rotated to new Orientation, view Information %@", self.view); } @end

  查看代碼我們可以發現,我們的viewController支持四個方向,然后在旋轉完成的didRotateFromInterfaceOrientation函數中打印了self.view的信息,旋轉一圈我們可以看到如下輸出:

  設備的初始方向是UIInterfaceOrientationPortrait的,然后順時針依次經過LandscapeLeftPortraitUpsideDownLandscapeRight,最后再回到UIInterfaceOrientationPortrait方向。仔細看的話我們會發現在旋轉的過程中,除了frame之外,Transform也在一直變化。觀察frame發現,它的變化應該是由於系統的狀態欄引起的。於是將系統狀態欄隱藏掉,在輸出發現frame果然不再變化。因此我們可以懷疑屏幕旋轉是通過變化Transform實現的。

 

二、什么是Transform

  Transform(變化矩陣)是一種3×3的矩陣,如下圖所示:

  通過這個矩陣我們可以對一個坐標系統進行縮放,平移,旋轉以及這兩者的任意組着操作。而且矩陣的操作不具備交換律,即矩陣的操作的順序不同會導致不同的結果。UIView有個transform的屬性,通過設置該屬性,我們可以實現調整該view在其superView中的大小和位置。

  矩陣實現坐標變化背后的數學知識:

  設x,y分別代表在原坐標系統中的位置,x',y'代表通過矩陣變化以后在新的系統中的位置。其中式1就是矩陣變化的公式,對式1進行展開以后就可以得到式2。從式2我們可以清楚的看到(x,y)到(x',y')的變化關系。

  1)當c,b,tx,ty都為零時,x' = ax,y' = by;即a,d就分別代表代表x,y方向上放大的比例;當a,d都為1時,x' = x,y' = y;這個時候這個矩陣也就是傳說中的CGAffineTransformIdentity(標准矩陣)。

  2)當a,d為1,c,b為零的時候,x' = x + tx,y' = y + ty;即tx,ty分別代表x,y方向上的平移距離。

  3)前面兩種情況就可以實現縮放和平移了,那么旋轉如何表示呢?

  假設不做平移和縮放操作,那么從原坐標系中的一點(x,y)旋轉α°以后到了新的坐標系中的一點(x',y'),那么旋轉矩陣如下:

  

  展開以后就是x' = xcosα - ysinα,y' = xsinα + ycosα;

 

  實際應用中,我們將這些變化綜合起來,即可完成所有二維的矩陣變化。現在我們在回過頭來看看前面設備旋轉時的輸出,當設備位於Portrait的時候由於矩陣是標准矩陣,所以沒有進行打印。當轉到UIInterfaceOrientationLandscapeLeft方向的時候,我們的設備是順時針轉了90°(逆時針為正,順時針為負),這個時候矩陣應該是(cos-90°,sin-90°,-sin-90°,cos-90°,tx,ty),由於未進行平移操作所以tx,ty都為0,剛好可以跟我們控制台輸出:"<UIView: 0x8075390; frame = (0 0; 320 480); transform = [0, -1, 1, 0, 0, 0]; autoresize = W+H; layer = <CALayer: 0x8074980>>"一致。觀察其他兩個方向的輸出,發現結果均和分析一致。

  由此可以發現屏幕旋轉其實就是通過view的矩陣變化實現,當設備監測到旋轉的時候,會通知當前程序,當前程序再通知程序中的windowwindow會通知它的rootViewController的,rootViewController對其viewtransform進行設置,最終完成旋轉。

  如果我們直接將一個view添加到window上,系統將不會幫助我們完成旋操作,這個時候我們就需要自己設置該viewtransform來實現旋轉了。這種情況雖然比較少,但是也存在的,例如現在很多App做的利用狀態欄進行消息提示的功能就是利用自己創建window並且自己設置transform來完成旋轉支持的,下一篇博客會介紹如何實現這種消息通知。

 

  注:轉載請注明出處!歡迎大家加我QQ 1592232964,一起討論共同進步。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM