在做視頻開發時遇到屏幕旋轉問題,其中涉及到 statusbar、 uinavigationcontroller、uitabbarcontroller 、uiviewcontroller
。
在設備鎖屏下的整體效果圖
ios-旋轉.gif
主要涉及以下4點:
- 橫豎屏的旋轉
- 屏幕旋轉相應改變視圖位置
- 旋轉時狀態欄的隱藏與顯示
- 鎖屏
1、橫豎屏旋轉
第1步:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
|
-(uiinterfaceorientationmask)application:(uiapplication *)application supportedinterfaceorientationsforwindow:(uiwindow *)window { // nslog(@"0000000---------%@",nsstringfromclass([[self topviewcontroller] class])); // if ([nsstringfromclass([[self topviewcontroller] class]) isequaltostring:@"firstviewcontroller"]) { // //橫屏 // return uiinterfaceorientationmasklandscaperight; // } // //豎屏 // return uiinterfaceorientationmaskportrait; nsuinteger orientations = uiinterfaceorientationmaskallbutupsidedown; if (self.window.rootviewcontroller){ //取出當前顯示的控制器 uiviewcontroller *presentedviewcontroller = [self topviewcontrollerwithrootviewcontroller:self.window.rootviewcontroller]; //按當前控制器支持的方向確定旋轉方向(將旋轉方向重新交給每個控制器自己控制) nslog(@ "%s, line = %d" ,__function__,__line__); orientations = [presentedviewcontroller supportedinterfaceorientations]; } return orientations; } //獲取界面最上層的控制器 //- (uiviewcontroller*)topviewcontroller { // nslog(@"%s, line = %d",__function__,__line__); // return [self topviewcontrollerwithrootviewcontroller:[uiapplication sharedapplication].keywindow.rootviewcontroller]; //} //一層一層的進行查找判斷 - (uiviewcontroller*)topviewcontrollerwithrootviewcontroller:(uiviewcontroller*)rootviewcontroller { nslog(@ "%s, line = %d" ,__function__,__line__); if ([rootviewcontroller iskindofclass:[uitabbarcontroller class ]]) { uitabbarcontroller* tabbarcontroller = (uitabbarcontroller*)rootviewcontroller; nslog(@ "tabbar:%@" ,nsstringfromclass([tabbarcontroller.selectedviewcontroller class ])); return [self topviewcontrollerwithrootviewcontroller:tabbarcontroller.selectedviewcontroller]; } else if ([rootviewcontroller iskindofclass:[uinavigationcontroller class ]]) { uinavigationcontroller* nav = (uinavigationcontroller*)rootviewcontroller; nslog(@ "nav:%@" ,nsstringfromclass([nav.visibleviewcontroller class ])); return [self topviewcontrollerwithrootviewcontroller:nav.visibleviewcontroller]; } else if (rootviewcontroller.presentedviewcontroller) { nslog(@ "present:%@" ,nsstringfromclass([rootviewcontroller.presentationcontroller class ])); uiviewcontroller* presentedviewcontroller = rootviewcontroller.presentedviewcontroller; return [self topviewcontrollerwithrootviewcontroller:presentedviewcontroller]; } else { nslog(@ "root:%@" ,rootviewcontroller); return rootviewcontroller; } } |
代碼中通過 -(uiinterfaceorientationmask)application:(uiapplication *)application supportedinterfaceorientationsforwindow:(uiwindow *)window
方法將控制器交給自己控制,該方法默認值為 info.plist
中配置的 supported interface orientations
項的值。
第2步:在各控制器設置支持的方向
1
2
3
4
5
6
7
8
9
|
//是否允許旋轉(默認允許) - ( bool )shouldautorotate { return yes; } - (uiinterfaceorientationmask)supportedinterfaceorientations{ //允許旋轉的方向 return uiinterfaceorientationmaskall; } |
其中 - supportedinterfaceorientations
方法在 ipad 中默認取值為 uiinterfaceorientationmaskall
,即默認支持所有屏幕方向;而 iphone 跟 ipod touch 的默認取值為 uiinterfaceorientationmaskallbutupsidedown
,即支持除豎屏向下以外的三個方向。
在設備屏幕旋轉時,系統會調用 - shouldautorotate
方法檢查當前界面是否支持旋轉,只有 - shouldautorotate
返回 yes
的時候, - supportedinterfaceorientations
方法才會被調用,以確定是否需要旋轉界面。
這個是 tabbarcontroller
中設置的,它會影響關聯的 uiviewcontroller
的支持方向,需要在 uiviewcontroller
中進一步設置
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
|
//此方法來控制能否橫豎屏 控制鎖屏 - (uiinterfaceorientationmask)supportedinterfaceorientations { nslog(@ "%s, line = %d" ,__function__,__line__); uiinterfaceorientationmask inter; if (_lockscreen) { switch (_lockorientation) { case 1: inter = uiinterfaceorientationmaskportrait; break ; case 2: inter = uiinterfaceorientationmaskportraitupsidedown; break ; case 3: inter = uiinterfaceorientationmasklandscaperight; break ; case 4: inter = uiinterfaceorientationmasklandscapeleft; break ; default :inter = uiinterfaceorientationmaskall; break ; } } else { inter = uiinterfaceorientationmaskall; } //支持全部方向 return inter; } |
第3步:強制轉換控制器方向
1
2
3
4
5
6
7
8
9
10
11
12
13
|
- ( void )setinterorientation:(uiinterfaceorientation)orientation { if ([[uidevice currentdevice] respondstoselector:@selector(setorientation:)]) { sel selector = nsselectorfromstring(@ "setorientation:" ); nsinvocation *invocation = [nsinvocation invocationwithmethodsignature:[uidevice instancemethodsignatureforselector:selector]]; [invocation setselector:selector]; [invocation settarget:[uidevice currentdevice]]; int val = orientation; // 從2開始是因為0 1 兩個參數已經被selector和target占用 [invocation setargument:&val atindex:2]; [invocation invoke]; } } |
這樣就可以完成橫豎屏的切換。
2、屏幕旋轉相應改變視圖位置
這里先擴展 uideviceorientation & uiinterfaceorientation
的知識
uideviceorientation
設備的物理方向
uideviceorientation
即我們手持的移動設備的 orientation
,是一個三圍空間,有六個方向,通過 [uidevice currentdevice].orientation
獲取當前設備的方向。
1
2
3
4
5
6
7
8
9
|
typedef ns_enum(nsinteger, uideviceorientation) { uideviceorientationunknown, uideviceorientationportrait, uideviceorientationportraitupsidedown, // device oriented vertically, home button on the top 豎屏向下,即頭在下,home 鍵在上 uideviceorientationlandscapeleft, // device oriented horizontally, home button on the right 橫屏頭在左,home鍵在右 uideviceorientationlandscaperight, // device oriented horizontally, home button on the left 橫屏頭在右,home鍵在左 uideviceorientationfaceup, // device oriented flat, face up uideviceorientationfacedown // device oriented flat, face down } ; |
uiinterfaceorientation
界面的顯示方向
uiinterfaceorientation
即我們看到的視圖的 orientation
,可以理解為 statusbar
所在的方向,是一個二維空間,有四個方向, 通過 [uiapplication sharedapplication].statusbarorientation
即狀態欄的方向獲取當前界面方向。
1
2
3
4
5
6
7
8
9
|
// note that uiinterfaceorientationlandscapeleft is equal to uideviceorientationlandscaperight (and vice versa). // this is because rotating the device to the left requires rotating the content to the right. typedef ns_enum(nsinteger, uiinterfaceorientation) { uiinterfaceorientationunknown = uideviceorientationunknown, uiinterfaceorientationportrait = uideviceorientationportrait, uiinterfaceorientationportraitupsidedown = uideviceorientationportraitupsidedown, uiinterfaceorientationlandscapeleft = uideviceorientationlandscaperight, uiinterfaceorientationlandscaperight = uideviceorientationlandscapeleft } |
uiinterfaceorientationmask
支持的方向
1
2
3
4
5
6
7
8
9
10
|
// ios 6 之后用于控制界面的枚舉值 typedef ns_options(nsuinteger, uiinterfaceorientationmask) { uiinterfaceorientationmaskportrait = (1 << uiinterfaceorientationportrait), uiinterfaceorientationmasklandscapeleft = (1 << uiinterfaceorientationlandscapeleft), uiinterfaceorientationmasklandscaperight = (1 << uiinterfaceorientationlandscaperight), uiinterfaceorientationmaskportraitupsidedown = (1 << uiinterfaceorientationportraitupsidedown), uiinterfaceorientationmasklandscape = (uiinterfaceorientationmasklandscapeleft | uiinterfaceorientationmasklandscaperight), uiinterfaceorientationmaskall = (uiinterfaceorientationmaskportrait | uiinterfaceorientationmasklandscapeleft | uiinterfaceorientationmasklandscaperight | uiinterfaceorientationmaskportraitupsidedown), uiinterfaceorientationmaskallbutupsidedown = (uiinterfaceorientationmaskportrait | uiinterfaceorientationmasklandscapeleft | uiinterfaceorientationmasklandscaperight), } |
由上可以發現:
ios 6 及之后版本使用的 uiinterfaceorientationmask
類型來控制屏幕屏幕方向,該類型也新增加了幾個枚舉取值,可用一個枚舉取值來代表多個屏幕方向,使用起來更方便。
注意在 uiinterfaceorientation
中有注釋
note that uiinterfaceorientationlandscapeleft is equal to uideviceorientationlandscaperight (and vice versa).
this is because rotating the device to the left requires rotating the content to the right,大意是界面的左轉相當于設備的右轉,如果設備向左轉時就需要內容(即界面)向右轉。即:
uiinterfaceorientationlandscapeleft = uideviceorientationlandscaperight
uiinterfaceorientationlandscaperight = uideviceorientationlandscapeleft
下面還會舉例說明。
其實 uideviceorientation
與 uiinterfaceorientation
是兩個互不相干的屬性,通常情況下會一起出現,在這里正好利用此特性在屏幕旋轉后進行重新布局。
第1步:監聽 uideviceorientationdidchangenotification
狀態
1
2
3
4
5
6
7
8
|
//監聽設備旋轉 改變 視圖 對應位置 [[nsnotificationcenter defaultcenter] addobserver:self selector:@selector(deviceorientationdidchange) name:uideviceorientationdidchangenotification object:nil]; //用來控制橫豎屏時調整視圖位置 - ( void )deviceorientationdidchange { [self isportrait]; } |
第2步:重新布局
1
2
3
4
5
6
7
8
|
if (_interorientation == uiinterfaceorientationportrait || _interorientation == uiinterfaceorientationportraitupsidedown) { self.top.constant = 145; self.bottom.constant = 210; } else if (_interorientation == uiinterfaceorientationlandscaperight || _interorientation == uiinterfaceorientationlandscapeleft) { self.top.constant = 40; self.bottom.constant = 50; } |
例如:豎屏轉橫屏
界面豎屏 uiinterfaceorientationportrait
->橫屏 uiinterfaceorientationlandscaperight
,設備方向 uideviceorientationportrait
-> uideviceorientationlandscapeleft
,在設備發生變化這個過程觸發 uideviceorientationdidchangenotification
監聽,然后進行重新布局。
3、旋轉時狀態欄的隱藏與顯示
這里只記述旋轉時狀態欄的變化,由豎屏想橫屏變化時狀態欄會消失。
1
2
3
4
5
|
//在需要的`uiviewcontroller`設置是否隱藏 - ( bool )prefersstatusbarhidden { nslog(@ "%s, line = %d" ,__function__,__line__); return no; } |
4、鎖屏
鎖屏時,不管系統鎖屏是否關閉、push 或 present 返回后,界面依然保持不變。
第1步:設置鎖屏
1
2
3
4
5
6
7
8
9
10
11
12
|
- (ibaction)lockaction:(uibutton *)sender { if (_lockscreen) { _lockscreen = no; [sender settitle:@ "鎖定屏幕" forstate:uicontrolstatenormal]; } else { _lockscreen = yes; [sender settitle:@ "解開屏幕" forstate:uicontrolstatenormal]; } _lockorientation = _interorientation; } |
第2步:繞過強轉
1
2
3
4
5
6
7
8
|
- ( void )interfaceorientation:(uiinterfaceorientation)orientation { [self isportrait]; //鎖屏情況下 不旋轉 if (!_lockscreen) { [self setinterorientation:orientation]; } |
第3步:針對 push 或 present 返回后
1
2
3
4
5
6
7
8
9
|
- ( void )viewwillappear:( bool )animated { if (_lockscreen) { //記錄返回時的界面狀態 [self setinterorientation:_lockorientation]; } else { [self isportrait]; } } |
5、 針對特定 uiviewcontroller
方向的支持
1
2
3
4
5
6
7
8
9
|
-(uiinterfaceorientationmask)application:(uiapplication *)application supportedinterfaceorientationsforwindow:(uiwindow *)window { if ([nsstringfromclass([[self topviewcontroller] class ]) isequaltostring:@ "firstviewcontroller" ]) { //橫屏 return uiinterfaceorientationmasklandscaperight; } //豎屏 return uiinterfaceorientationmaskportrait; } |
最后的獻上 github 代碼,還有2個小的 bug ,有興趣的朋友歡迎來探討。
以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持服務器之家。
原文鏈接:https://www.jianshu.com/p/5f82baaab740