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 
} 
相关问题