不少時候,項目中都有這樣的需求:APP中以豎屏爲主,個別界面會要求橫屏顯示,或者要根據用戶的手機朝向自動切換橫豎屏;下面就來詳細講解,在項目中怎麼使用代碼來控制APP的界面轉換.
首先,要想APP支持多個方向,須要在工程進行設置支持的朝向:
在General-->Deployment Info-->Device Orientation
中進行設置
git
這樣,就能夠在項目中使用代碼來控制頁面的朝向了,在這以前,須要知道控制視圖是否可以自動旋轉,以及支持的朝向,是經過哪些方法來控制的?
其實,主要使用的是下面三個方法:github
// New Autorotation support. //是否自動旋轉,返回YES能夠自動旋轉 - (BOOL)shouldAutorotate NS_AVAILABLE_IOS(6_0) __TVOS_PROHIBITED; //返回支持的方向 - (UIInterfaceOrientationMask)supportedInterfaceOrientations NS_AVAILABLE_IOS(6_0) __TVOS_PROHIBITED; // Returns interface orientation masks. //這個是返回優先方向 - (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation NS_AVAILABLE_IOS(6_0) __TVOS_PROHIBITED;
通常狀況下,實現前兩個方法便可!這些都是UIViewController的實例方法,直接在須要設置的控制器內重寫上面的方法便可;
有時候,你會發現,只有在APP啓動時出現的第一個界面內重寫上面的兩個方法,會有效果;而在其餘的界面重寫,並無效果.這是由於,程序啓動後的第一個界面是程序的跟視圖控制器,而這些設置,必須是影響了跟視圖中的相應設置,纔會有效果;
假如,你在跟視圖中進行了以下設置:數組
- (BOOL)shouldAutorotate{ return NO; }
那麼,在整個項目中,不管你如何設置,都不會有自動旋轉屏幕的效果.
綜上可知,若是要改變某個視圖屏幕方向,須要告訴跟視圖,在跟視圖中修改成相應的設置便可;
因此,問題來了,怎麼告訴跟視圖呢?這要視狀況而定:app
這種狀況最簡單,直接在控制器中重寫上面的方法,設置是否支持自動旋轉,以及支持的方向便可:ide
- (BOOL)shouldAutorotate{ return YES; } #if __IPHONE_OS_VERSION_MAX_ALLOWED < __IPHONE_9_0 - (NSUInteger)supportedInterfaceOrientations #else - (UIInterfaceOrientationMask)supportedInterfaceOrientations #endif { return UIInterfaceOrientationMaskAll; }
像上面我設置爲支持自動旋轉,支持全部的朝向;
這種方式, 切換視圖的方式主要是模態(present), 只須要在相應的UIViewController裏重寫上面的方法便可.
可是這種狀況不多見...
對應的demo爲:LZInterfaceRotation中的Rotation-UIViewControllerpost
這種狀況比較常見,也很簡單;通常使用的導航的時候,都不會去直接使用系統的UINavigationController,而會定義一個他的子類,作一些公共的設置:spa
#import <UIKit/UIKit.h> @interface BaseNaviViewController : UINavigationController @end
而後在導航的viewController裏面重寫上面的三個方法,這裏也有兩種方式來控制:code
這種方式,主要是用在,當push到某個視圖控制器時,要求他可以支持自動旋轉,或者強制轉爲橫屏;這裏主要用到了導航的viewControllers
屬性,這是一個數組,數組的最後一個元素,就是最後push進去的viewController,因此,實現代碼以下:視頻
-(BOOL)shouldAutorotate { return [[self.viewControllers lastObject] shouldAutorotate]; } #if __IPHONE_OS_VERSION_MAX_ALLOWED < __IPHONE_9_0 - (NSUInteger)supportedInterfaceOrientations #else - (UIInterfaceOrientationMask)supportedInterfaceOrientations #endif { return [[self.viewControllers lastObject] supportedInterfaceOrientations]; } - (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation { return [[self.viewControllers lastObject] preferredInterfaceOrientationForPresentation]; }
到這裏尚未結束,這裏只是獲取到了最後一個push的viewController,而後用它去調用了相應的方法,具體的方法實現,仍是須要在哪一個viewController裏進行設置的,也就是在須要特殊設置的viewController裏重寫上面的方法:server
-(BOOL)shouldAutorotate { return YES; } #if __IPHONE_OS_VERSION_MAX_ALLOWED < __IPHONE_9_0 - (NSUInteger)supportedInterfaceOrientations #else - (UIInterfaceOrientationMask)supportedInterfaceOrientations #endif { return UIInterfaceOrientationMaskPortraitUpsideDown; } - (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation { return UIInterfaceOrientationPortraitUpsideDown; }
其實這樣也就是告訴跟視圖控制器,這個界面我要特殊設置一下;
對應的demo爲: LZInterfaceRotation中的Rotation-UINavigationController
第一種方法是,只要push進去一個視圖控制器,均可以進行相應的設置,而這種方法是隻針對特定的控制器進行設置,例如這裏,我須要把SecondViewController
單獨設置爲支持橫屏,只須要將第一種方法中的導航裏的相應代碼作以下修改:
-(BOOL)shouldAutorotate { if ([[self.viewControllers lastObject]isKindOfClass:[SecondViewController class]]) { return YES; } return NO; } #if __IPHONE_OS_VERSION_MAX_ALLOWED < __IPHONE_9_0 - (NSUInteger)supportedInterfaceOrientations #else - (UIInterfaceOrientationMask)supportedInterfaceOrientations #endif { if ([[self.viewControllers lastObject]isKindOfClass:[SecondViewController class]]) { return UIInterfaceOrientationMaskLandscapeLeft; } return UIInterfaceOrientationMaskPortrait; } - (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation { if ([[self.viewControllers lastObject]isKindOfClass:[SecondViewController class]]) { return UIInterfaceOrientationLandscapeLeft; } return UIInterfaceOrientationPortrait; }
這樣的好處是,能夠控制指定的視圖控制器,也不用在指定的視圖控制器內再重寫上面的方法;
壞處就是,若是須要控制的視圖控制器比較多的話,加的判斷會多不少;沒有方式一靈活;
對應的demo爲: LZInterfaceRotation中的Rotation-UINavigationController副本
這種狀況比較常見,項目的跟視圖控制器是一個UITabBarController
,這種狀況的實現相對來講要複雜一些,可是,明白了原理,老是有方法來實現的.歸根結底,也就是告訴跟視圖,我這個界面須要支持旋轉了;
因爲,在UITabBarController
裏直接獲取到UIViewController
比較困難,因此這裏我採用通知的形式,來獲取相應的設置狀態;
首先,設置一個全局的BOOL值,用於接收通知發送的參數:
#import <UIKit/UIKit.h> @interface BaseTabBar : UITabBarController { BOOL shouldAutorotate; } @end
而後註冊一個通知:
//註冊旋轉屏幕的通知 [[NSNotificationCenter defaultCenter]addObserver:self selector:@selector(autorotateInterface:) name:@"InterfaceOrientationNotification" object:nil];
實現通知方法:
-(void)autorotateInterface:(NSNotification *)notifition { shouldAutorotate = [notifition.object boolValue]; }
而後在重寫的方法里加入判斷:
/** * * @return 是否支持旋轉 */ -(BOOL)shouldAutorotate { NSLog(@"======%d",shouldAutorotate); return shouldAutorotate; } /** * 適配旋轉的類型 * * @return 類型 */ -(UIInterfaceOrientationMask)supportedInterfaceOrientations { if (!shouldAutorotate) { return UIInterfaceOrientationMaskPortrait; } return UIInterfaceOrientationMaskAllButUpsideDown; }
這裏我直接將支持的方向寫死了,只是判斷了一下是否支持自動旋轉屏幕,若是須要將支持的方向傳過來,能夠修改通知攜帶的參數;
最後在須要自動轉屏的控制器內發送通知:
[[NSNotificationCenter defaultCenter] postNotificationName:@"InterfaceOrientationNotification" object:@"YES"];
對應的demo爲: LZInterfaceRotation中的Rotation-UITabBarController
PS新增: 關於什麼時候發送通知
例若有這樣的需求: A豎屏, 不能自動旋轉, B 可橫屏可豎屏可自動旋轉, 並且在從B回到A的時候, 若是不是豎屏, 強制轉爲豎屏, 這就用到了下面強制轉屏的方法;
咱們在使用的時候確定是在B的viewWillAppear方法裏發送通知告訴跟視圖要自動旋轉, 而在離開這個視圖時, 就有可能會在viewWillDisappear方法裏發送不能自動旋轉的通知, 這樣是不能實現效果的, 應該放在viewDidDisappear方法裏發送;
爲嚴謹起見, 建議在viewDidAppear方法裏發送能夠自動旋轉的通知, 在viewDidDisappear方法裏發送不能夠自動選擇的通知.
這裏使用的通知來告知跟視圖是否自動旋轉, 也可使用NSUserDefaults 來傳遞這個值, 或者單例均可以.
到此,對於控制屏幕的旋轉及方向,基本就介紹完了,若是有不足或者不對的地方,還請指正;若是你有更好的方式實現一樣的效果,還請不吝賜教...
最後介紹一個強制旋轉屏幕的方法,這個方法能夠在進入某個視圖時,強制轉成你須要的屏幕方向,用的比較多的是在一個豎屏的應用中強制轉換某一個界面爲橫屏(例如播放視頻):
PS: 這個方法的使用有個前提, 必定是在跟視圖的-(BOOL)shouldAutorotate返回值爲YES的時候纔有效.
//強制旋轉屏幕 - (void)orientationToPortrait:(UIInterfaceOrientation)orientation { SEL selector = NSSelectorFromString(@"setOrientation:"); NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:[UIDevice instanceMethodSignatureForSelector:selector]]; [invocation setSelector:selector]; [invocation setTarget:[UIDevice currentDevice]]; int val = orientation; [invocation setArgument:&val atIndex:2];//前兩個參數已被target和selector佔用 [invocation invoke]; }
使用的時候,只須要把你須要旋轉的方向傳過去便可!
有一點須要注意:從A進入B的時候, 把B強制轉換成橫屏,返回的時候,須要在A出現的時候再轉換爲原來的方向,否則會有問題;我的建議能夠在B的viewWillAppear調用這個方法,轉換屏幕(例如轉換爲橫屏),而後在A的viewWillAppear中轉換回來; 若是使用通知來告訴跟視圖是否能夠自動旋轉, 這個方法要在通知發送以後調用.
具體效果及設置, 可參考demo: LZInterfaceRotation