31

我有一個UIWebView包含在UIViewController這是UINavigationController的後代。它看起來像這樣:允許唯一肖像應用程序的風景視頻

Main view

應用程序是唯一的肖像。當我播放視頻時,我希望用戶能夠旋轉設備並以橫向模式查看視頻。我用這個代碼,允許它:

- (NSUInteger)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window 
{ 
    id presentedViewController = [self topMostController]; 
    NSString *className = presentedViewController ? NSStringFromClass([presentedViewController class]) : nil; 

    if ([className isEqualToString:@"MPInlineVideoFullscreenViewController"] || 
     [className isEqualToString:@"MPMoviePlayerViewController"] || 
     [className isEqualToString:@"AVFullScreenViewController"]) { 
     return UIInterfaceOrientationMaskAllButUpsideDown; 
    } 

    return UIInterfaceOrientationMaskPortrait; 
} 

- (UIViewController *)topMostController { 
    UIViewController *topController = [UIApplication sharedApplication].keyWindow.rootViewController; 

    while (topController.presentedViewController) { 
     topController = topController.presentedViewController; 
    } 

    return topController; 
} 

然後在我的UINavigationController(所以當視頻結束的觀點並沒有在景觀呈現,但只有在人像):

- (BOOL)shouldAutorotate 
{ 
    return NO; 
} 

- (NSUInteger)supportedInterfaceOrientations 
{ 
    return UIInterfaceOrientationMaskPortrait; 
} 

- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation 
{ 
    return UIInterfaceOrientationPortrait; 
} 

一切完美:

Video portraitVideo landscape

但隨後的視頻播放完畢(或用戶點擊「完成」)和屏幕返回底層來看,這是發生了什麼:

Navigation bar issue

正如你所看到的,導航欄,狀態欄下滑動。 此外,我在日誌中收到很多自動佈局錯誤:http://pastebin.com/09xHzmgJ

有關如何解決此問題的任何想法?

+0

什麼是你的項目的設置(代碼之外?) – 2015-08-18 20:58:29

+0

@entropid你有沒有爲此打開一個雷達?在iOS 10上仍然存在問題... – 2017-01-10 16:59:50

回答

17

我暫時解決了(通過黑客)與我的控制器的viewDidLoad中的以下代碼。我必須指定代碼是專門爲我的情況製作的:由於我明確禁止使用UINavigationController的橫向(請參閱上面的代碼),因此當播放完成並且窗口返回到縱向時,不會調用通常的「UIDeviceOrientationDidChange」通知。不過,我希望有一個更好的選擇,這是SDK的一個錯誤,因爲它不會出現在iOS 7上,並且給出了與視頻播放器相關的自動佈局錯誤的數量(我無法控制它) 。

- (void)viewDidLoad 
{ 
    [super viewDidLoad]; 

    // […] 

    /* 
    Hack to fix navigation bar position/height on iOS 8 after closing fullscreen video 

    Observe for 「UIWindowDidRotateNotification」 since 「UIDeviceOrientationDidChangeNotification」 is not called in the present conditions 
    Check if the notification key (「UIWindowOldOrientationUserInfoKey」) in userInfo is either 3 or 4, which means the old orientation was landscape 
    If so, correct the frame of the navigation bar to the proper size. 

    */ 
    [[NSNotificationCenter defaultCenter] addObserverForName:@"UIWindowDidRotateNotification" object:nil queue:nil usingBlock:^(NSNotification *note) { 
     if ([note.userInfo[@"UIWindowOldOrientationUserInfoKey"] intValue] >= 3) { 
      self.navigationController.navigationBar.frame = (CGRect){0, 0, self.view.frame.size.width, 64}; 
     } 
    }]; 
} 

然後......

- (void)dealloc 
{ 
    [[NSNotificationCenter defaultCenter] removeObserver:self forKeyPath:@"UIWindowDidRotateNotification"]; 
} 
+0

您也可以查看UINavigationBar的子類並覆蓋setCenter/setFrame/setBounds。當我需要細粒度的控制時,我這樣做了。 – 2014-10-28 21:39:04

+0

我會嘗試,但它是一個UINavigationController,所以我不知道我可以在導航欄上控制多少。此外,身高的變化是由一些奇怪的限制引起的,因此我不太確定。 – entropid 2014-10-29 10:36:05

+0

工程太棒了!謝謝 – AleyRobotics 2015-04-16 10:36:30

5

我遇到了一模一樣的問題,並使用相同的代碼@entropid一樣。然而,接受的解決方案並不適合我。

我花了時間來與下面的一行修復程序做的事情爲我工作:

- (void)viewWillLayoutSubviews { 
    [[UIApplication sharedApplication] setStatusBarHidden:NO withAnimation:UIStatusBarAnimationNone]; 
} 
+0

我會盡快嘗試,如果有效,我會接受它作爲「解決方案」;它比我的黑客要好得多。 – entropid 2015-02-09 15:01:50

+0

是的,這將是很好的知道它是否適合你。 – 2015-02-09 18:22:07

+3

是的,這應該是可接受的解決方案。確認工作正常。 – 2015-04-27 04:04:02

3

斯威夫特版本:

//AppDelegate: 
    func application(application: UIApplication, supportedInterfaceOrientationsForWindow window: UIWindow?) -> Int { 

     var presentedVC = application.keyWindow?.rootViewController 
     while let pVC = presentedVC?.presentedViewController 
     { 
      presentedVC = pVC 
     } 
     if let pVC = presentedVC 
     { 
      if contains(["MPInlineVideoFullscreenViewController", "MPMoviePlayerViewController", "AVFullScreenViewController"], pVC.nameOfClass) 
      { 
       return Int(UIInterfaceOrientationMask.AllButUpsideDown.rawValue) 
      } 
     } 

     return Int(UIInterfaceOrientationMask.Portrait.rawValue) 
    } 

//Extension: 
public extension NSObject{ 
    public class var nameOfClass: String{ 
     return NSStringFromClass(self).componentsSeparatedByString(".").last! 
    } 

    public var nameOfClass: String{ 
     return NSStringFromClass(self.dynamicType).componentsSeparatedByString(".").last! 
    } 
} 

//View controller: 
    override func supportedInterfaceOrientations() -> Int { 
     return Int(UIInterfaceOrientationMask.Portrait.rawValue) 
    } 

    override func preferredInterfaceOrientationForPresentation() -> UIInterfaceOrientation { 
     return UIInterfaceOrientation.Portrait 
    } 

    override func shouldAutorotate() -> Bool { 
     return false 
    } 

    override func viewWillLayoutSubviews() { 
     UIApplication.sharedApplication().setStatusBarHidden(false, withAnimation: UIStatusBarAnimation.None) 
    } 
-1

我對這個問題的答案的偉大工程。 Here它會在您的WebView內正常播放視頻,但如果您傾斜手機,它將在橫向播放!

同樣重要的是要注意的是,如果您將youtube.com作爲基本URL加載,則加載速度會更快。

在故事板中創建一個UIWebView並將@property連接到它,然後在下面參考。

CGFloat width = self.webView.frame.size.height; 
    CGFloat height = self.webView.frame.size.width; 
    NSString *youTubeVideoCode = @"dQw4w9WgXcQ"; 
    NSString *embedHTML = @"<iframe width=\"%f\" height=\"%f\" src=\"http://www.youtube.com/embed/%@\" frameborder=\"0\" style=\"margin:-8px;padding:0;\" allowfullscreen></iframe>"; 
    NSString *html = [NSString stringWithFormat:embedHTML, width, height, youTubeVideoCode]; 
    self.webView.scrollView.bounces = NO; 
    [self.webView loadHTMLString:html baseURL:[NSURL URLWithString:@"http://www.youtube.com"]]; 
0

我有同樣的問題,並使用@entropid解決方案我能夠解決導航欄問題。但我的觀點仍然在我使用「sizeToFit」修復的導航欄下方。

[[NSNotificationCenter defaultCenter] addObserverForName:@"UIWindowDidRotateNotification" object:nil queue:nil usingBlock:^(NSNotification *note) { 
    if ([note.userInfo[@"UIWindowOldOrientationUserInfoKey"] intValue] >= 3) { 
     [self.navigationController.navigationBar sizeToFit]; 
     self.navigationController.navigationBar.frame = (CGRect){0, 0, self.view.frame.size.width, 64}; 
    } 
}]; 

我還沒有適當的測試,但它的工作對我來說,現在

4

我昨天遇到這個問題,其中@entropid回答工作了iOS版9以下,但針對iOS 10事與願違(因爲iOS 10確實隱藏了狀態欄,在iOS 9和更低版本的情況下,它僅僅是UINavigationBar,它改變了它的框架而沒有隱藏狀態欄,因此它與該欄重疊)。

此外,訂閱MPMoviePlayerControllerDidExitFullScreen通知沒有任何工作,有時乾脆不叫(在我的具體情況,這是因爲它是從UIWebView的視頻,它使用播放器的不同類類似於到MPMoviePlayerController)。

所以我解決它使用類似@StanislavPankevich提出的一個解決方案,但我訂閱了通知,當UIWindow已成爲隱藏的(這在一些情況下,比如當視頻播放結束後,還當UIActivityViewController駁回和其他情況)而不是viewWillLayoutSubviews。對於我的特殊情況(UINavigationController的子類),像viewDidAppear,viewWillAppear等方法根本沒有被調用。

viewDidLoad中

- (void)viewDidLoad { 
    [super viewDidLoad]; 

    [[NSNotificationCenter defaultCenter] addObserver:self 
              selector:@selector(videoDidExitFullscreen:) 
               name:UIWindowDidBecomeHiddenNotification 
               object:nil]; 

    // Some other logic... 
} 

的dealloc

- (void)dealloc { 
    [[NSNotificationCenter defaultCenter] removeObserver:self]; 
} 

最後,videoDidExitFullscreen

- (void)videoDidExitFullscreen:(NSNotification *)notification { 
    // You would want to check here if the window dismissed was actually a video one or not. 

    [[UIApplication sharedApplication] setStatusBarHidden:NO 
              withAnimation:UIStatusBarAnimationFade]; 

} 

我使用UIStatusBarAnimationFade,因爲它看起來比UIStatusBarAnimationNone平滑得多,至少從用戶的角度來看。

0

在iOS 11上接受的解決方案對我無效。似乎導航欄停止反映框架更改。但有一個解決方法。首先,我們需要修改supportedInterfaceOrientationsForWindow方法,將視頻控制器的UIInterfaceOrientationMaskLandscape而不是UIInterfaceOrientationMaskAllButUpsideDown返回。在我的情況下,當我點擊嵌入的YouTube視頻時,系統總是打開AVFullScreenViewController,所以我從原始示例中刪除了其他檢查。代碼:

- (UIInterfaceOrientationMask)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window { 
    __kindof UIViewController *presentedViewController = [self topMostController]; 

    // Allow rotate videos 
    NSString *className = presentedViewController ? NSStringFromClass([presentedViewController class]) : nil; 
    if ([className isEqualToString:@"AVFullScreenViewController"]) { 
     return UIInterfaceOrientationMaskLandscape; 
    } 

    return UIInterfaceOrientationMaskPortrait; 
} 

這確實AVFullScreenViewController不改變行爲iOS上的10少了,但在iOS上11修復導航欄,所以沒有必要更新幀(也有在iOS上11副作用該視頻在開始播放時從橫向旋轉,但這是一個折衷)。接下來,我們需要在UIWindowDidBecomeHiddenNotification添加方法檢查:

- (void)videoDidExitFullscreen { 
    if (@available(iOS 11, *)) { 
     // Fixes status bar on iPhone X 
     [self setNeedsStatusBarAppearanceUpdate]; 
    } else { 
     self.navigationController.navigationBar.frame = CGRectMake(0, 0, self.view.bounds.size.width, statusAndNavBarHeight); 
    } 
} 

沒有setNeedsStatusBarAppearanceUpdate文本在狀態欄不會出現在iPhone X,它是沒有必要的其它設備。

1

這很簡單,因爲它@Stanislav Pankevich說,但在

SWIFT 3版

override func viewWillLayoutSubviews() { 
    super.viewWillLayoutSubviews(); 
    UIApplication.shared.isStatusBarHidden = false 
} 
相關問題