Ios 仅允许使用纵向应用程序在横向上播放视频

Ios 仅允许使用纵向应用程序在横向上播放视频,ios,objective-c,uiwebview,uinavigationcontroller,screen-rotation,Ios,Objective C,Uiwebview,Uinavigationcontroller,Screen Rotation,我有一个包含在UIViewController中的UIWebView,它是UINavigationController的后代。看起来是这样的: 该应用程序仅限于肖像。当我播放视频时,我希望用户能够旋转设备并以横向模式观看视频。我使用此代码来允许它: - (NSUInteger)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window { id p

我有一个包含在UIViewController中的UIWebView,它是UINavigationController的后代。看起来是这样的:

该应用程序仅限于肖像。当我播放视频时,我希望用户能够旋转设备并以横向模式观看视频。我使用此代码来允许它:

- (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中(因此,当视频结束时,视图不会以横向显示,而仅以纵向显示):

一切都很完美:

但随后视频播放完毕(或用户点击“完成”),屏幕返回到基础视图,如下所示:

如您所见,导航栏滑到状态栏下。 此外,我在日志中发现许多自动布局错误:

你知道如何解决这个问题吗?

我在控制器的
viewDidLoad
中用以下代码临时解决了(通过黑客攻击)。我必须指定代码是专门针对我的情况编写的:因为我明确禁止UINavigationController的横向定向(请参见上面的代码),所以在播放完成且窗口返回到纵向时,通常不会调用通知“UIDeviceOrientationIDChange”。然而,我希望有一个更好的选择,这是SDK的一个缺陷,因为它不会出现在iOS 7上,并且考虑到与视频播放器相关的自动布局错误数量(我无法控制)

然后

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

我遇到了与@entropid完全相同的问题,并使用了相同的代码。然而,被接受的解决方案对我不起作用

我花了好几个小时才想出了以下一行解决方案,使我的工作顺利进行:

- (void)viewWillLayoutSubviews {
    [[UIApplication sharedApplication] setStatusBarHidden:NO withAnimation:UIStatusBarAnimationNone];
}
Swift版本:

//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)
    }

我对这个问题的回答很有效。它将在您的网络视图内正常播放视频,但如果您倾斜手机,它将在横向播放

另外需要注意的是,如果你将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"]];
CGFloat width=self.webView.frame.size.height;
CGFloat height=self.webView.frame.size.width;
NSString*youTubeVideoCode=@“dQw4w9WgXcQ”;
NSString*embedHTML=@;
NSString*html=[NSString stringWithFormat:embedHTML、宽度、高度、youTubeVideoCode];
self.webView.scrollView.bounces=否;
[self.webView loadHTMLString:html baseURL:[NSURL URLWithString:@]http://www.youtube.com"]];

我遇到了同样的问题,使用@entropid解决方案,我能够解决导航栏问题。但我的视图仍位于导航栏下方,我使用“sizeToFit”来修复导航栏


我还没有对它进行正确的测试,但它现在对我起作用了

我昨天遇到了这个问题,@entropid answer对iOS 9及以下版本有效,但对iOS 10却没有(由于iOS 10实际上隐藏了状态栏,而在iOS 9及其以下版本中,只有
UINavigationBar
更改了其帧,而没有隐藏状态栏,因此,它与状态栏重叠)

另外,订阅
mpmovieplayercontrollerdiexitfullscreen
通知也不起作用,有时它根本就没有被调用(在我的特殊情况下,这是因为它是一个来自
UIWebView
的视频,它使用了一个与
MPMoviePlayerController
类似的不同级别的播放器)

因此,我使用@StanislavPankevich建议的解决方案解决了这个问题,但我订阅了
UIWindow
隐藏时的通知(在几种情况下,例如视频完成时,以及
UIActivityViewController
关闭和其他情况下)而不是
viewWillLayoutSubviews
。对于我的特殊情况(UINavigationController的子类
UINavigationController
),像
viewdidbeen
viewwillbeen
等方法根本没有被调用

viewDidLoad

- (void)viewDidLoad {
    [super viewDidLoad];

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

    // Some other logic...
}
解除锁定

- (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
,因为它看起来比
uistatusbaranimationne
平滑得多,至少从用户的角度来看是这样。

在iOS 11上接受的解决方案对我不起作用。导航栏似乎不再反映帧更改。但有一个解决方法。首先,我们需要修改
supportedInterFaceOrientionsForWindow
方法返回视频控制器的
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;
}
这并没有改变iOS 10及更低版本上AVFullScreenViewController的行为,但修复了iOS 11上的导航栏,因此无需更新帧(iOS 11上也有一个副作用,即视频在开始播放时从横向旋转,但这是一个折衷).接下来,我们需要添加签入
UIWindowDiBecomeHiddenNotification
方法:

- (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上,对于其他设备它是不需要的。

它非常简单,如@Stanislav Pankevich所说,但在

swift 3版本

override func viewWillLayoutSubviews() {
    super.viewWillLayoutSubviews();
    UIApplication.shared.isStatusBarHidden = false
}

您还可以查看子类化UINavigationBar和重写setCenter/setFrame/setBounds。我在需要细粒度控制时这样做了。我会尝试这样做,但它是一个UINavigationController,所以我不知道我可以在导航栏上拥有多少控制。此外,高度的变化是由一些奇怪的约束引起的,这些约束打破了,所以我不知道太确定了。我会很快尝试这个,如果它有效,我会接受它作为一个“解决方案”;这是一个比我更好的黑客。是的,这应该是被接受的解决方案。确认正常工作。你是一个天才。工作得很有魅力。设置是什么
- (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;
}
- (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);
    }
}
override func viewWillLayoutSubviews() {
    super.viewWillLayoutSubviews();
    UIApplication.shared.isStatusBarHidden = false
}