iOS螢幕旋轉之為橫屏視訊播放增加豎屏模式
阿新 • • 發佈:2019-01-24
在App Store上的大部分視訊播放App中,都實現了豎屏小屏播放以顯示更多相關資訊,橫屏切換到全屏播放,這樣的互動顯得優雅而大方。最近專案裡有個這樣的需求,為全屏視訊播放加上豎屏模式。下面,讓我們一起來實現這個需求。
iOS中的方向
iOS裝置中有兩種方向,一種是裝置方向,一種是螢幕檢視方向。我們可以直接呼叫
[UIDevice currentDevice] setOrientation:UIInterfaceOrientationPartrait];
強制更改裝置方向,但該方法已經在iOS6中廢止。另外一種更改裝置方向的方法是通過重力感應觸發。
那麼檢視方向是又什麼決定的呢?
- 全域性Info.plist
- iOS6+在UIApplicationDelegate中增加了 - (NSUInteger)supportedInterfaceOrientationsForWindow:(UIWindow *)window;回撥
- UIViewController。並且只在UIWindow的rootViewController或model狀態下的UIViewController有效
最終的檢視方向取決於 (全域性控制 ∩ UIWindow 中的回撥 ∩ 單個介面控制) 的交集,如果交集為空,iOS6下丟擲 UIApplicationInvalidInterfaceOrientationException 異常後崩潰。
UIController中對檢視方向變化的響應
iOS5:
-(BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation
{
return ((toInterfaceOrientation == UIInterfaceOrientationLandscapeRight) |
(toInterfaceOrientation == UIInterfaceOrientationLandscapeLeft));
}
iOS6+:
// 支援轉屏? (BOOL)shouldAutorotate { return YES; } // 支援的螢幕方向 - (NSUInteger)supportedInterfaceOrientations { return UIInterfaceOrientationMaskLandscape; }
實現前後的效果
豎屏: 橫屏:兩張橫豎屏的圖片中,選單、標題大小都發生了改變。下面我們就來討論下實現的方法。
實現細節
- 首先在視訊播放所在UIViewController支援橫豎屏,並在裝置旋轉的回撥中,通知選單當前的裝置方向發生了改變,程式碼如下:
willRotateToInterfaceOrientation:duration: 和 willAnimateRotationToInterfaceOrientation:duration:的區別在於呼叫的順序。前者在旋轉前呼叫,並且螢幕方向、裝置原點、檢視大小等都未改變,後者在旋轉的動畫block中呼叫,並且螢幕方向、裝置原點、檢視大小等都已改變。因此在willRotateToInterfaceOrientation:duration:中,應當做變數的更改;在willAnimateRotationToInterfaceOrientation:duration:中,適合做一些重繪工作。//裝置旋轉前 - (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration { //橫豎屏變更選單等 if (toInterfaceOrientation == UIInterfaceOrientationPortrait) { //豎屏狀態 } //裝置旋轉前 - (void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration { //對檢視進行旋轉處理,這裡通過present一個新的UIViewController,暫不需要處理 } //裝置旋轉完 - (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation { //裝置旋轉完的處理 } // 支援轉屏 (BOOL)shouldAutorotate { return YES; } // 支援的螢幕方向 - (NSUInteger)supportedInterfaceOrientations { return UIDeviceOrientationLandscapeLeft | UIInterfaceOrientationPortrait ; } -(BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation { return ((toInterfaceOrientation == UIInterfaceOrientationPortrait) || (toInterfaceOrientation == UIInterfaceOrientationLandscapeLeft)); }
- 考慮到原來的視訊播放器只支援橫屏播放,這裡採用的方案如下:豎屏狀態下,先present一個只支援橫屏的UIViewController,再將視訊播放器作為橫屏UIViewController的子控制器新增進來。這樣可以觸發iOS進行橫豎屏檢測。
- 當豎屏切到橫屏時,旋轉的動畫設定。程式碼如下:
[portraitViewController presentViewController:landscapeViewController animated:NO completion:^{ //mvPlayer原先是作為protraitViewController的子UIViewController [mvPlayer.view removeFromSuperview]; [mvPlayer removeFromParentViewController]; //改為作為landscapeViewController的子UIViewController [landscapeViewController addChildViewController:mvPlayer]; [landscapeViewController.view addSubview:mvPlayer.view]; //改變狀態列方向 [[UIApplication sharedApplication] setStatusBarHidden:YES]; [[UIApplication sharedApplication] setStatusBarOrientation:UIInterfaceOrientationLandscapeLeft animated:NO]; //旋轉前 CGAffineTransform transform = CGAffineTransformMakeRotation(-M_PI_2); transform = CGAffineTransformScale(transform, scale, scale); mvPlayer.view.transform = transform; //旋轉動畫 [UIView animateWithDuration:[[UIApplication sharedApplication] statusBarOrientationAnimationDuration] animations:^{ mvPlayer.view.transform = CGAffineTransformIdentity; mvPlayer.view.frame = landscapeViewController.view.bounds; }completion:^(BOOL finished) { [[UIApplication sharedApplication] setStatusBarHidden:NO]; }]; }];
- 橫屏切換到豎屏的動畫實現如下:
//更改mvPlayer的父UIController [mvPlayer.view removeFromSuperview]; UIViewController *viewController = strongSelf.player.presentingViewController; [mvPlayer removeFromParentViewController]; [viewController dismissModalViewControllerAnimated:NO]; [portraitViewController addChildViewController:mvPlayer]; [portraitViewController.view addSubview:mvPlayer.view]; //縮放動畫 CGAffineTransform transform = CGAffineTransformMakeScale(scale, scale); mvPlayer.view.transform = transform; mvPlayer.view.frame = CGRectMake(0, 0, CGRectGetWidth(mvPlayer.view.frame), CGRectGetHeight(mvPlayer.view.frame)); mvPlayer.view.transform = CGAffineTransformRotate(transform, M_PI_2); [UIView animateWithDuration:[[UIApplication sharedApplication] statusBarOrientationAnimationDuration] animations:^{ mvPlayer.view.transform = CGAffineTransformMakeScale(scale, scale); } completion:^(BOOL finished) { mvPlayer.view.frame = CGRectMake(0, 0, CGRectGetWidth(mvPlayer.view.frame), CGRectGetHeight(mvPlayer.view.frame)); }];
-
以上是手動旋轉過程。還有一種方法是直接旋轉portraitViewController.view。人為旋轉過程中,裝置的原點並未發生改變,這需要考慮橫豎屏佈局問題。
總結
本文介紹橫豎屏切換的一些基礎知識,並實踐了類似騰訊視訊的橫豎屏人為切換方式,達到不同狀態下顯示不同檢視的互動方式。