我有一个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中(所以当视频完成时,视图不是以横向呈现,而是仅以纵向呈现):
- (BOOL)shouldAutorotate
{
return NO;
}
- (NSUInteger)supportedInterfaceOrientations
{
return UIInterfaceOrientationMaskPortrait;
}
- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation
{
return UIInterfaceOrientationPortrait;
}
一切都很完美:
但视频已完成播放(或用户点击“完成”),屏幕返回基础视图,这就是:
如您所见,导航栏在状态栏下滑动。 此外,我在日志中遇到了很多自动布局错误:http://pastebin.com/09xHzmgJ
有关如何解决此问题的想法吗?
答案 0 :(得分:17)
我在控制器的viewDidLoad
中使用以下代码暂时解决(通过 hack )。我必须指定代码专门针对我的情况:因为我明确禁止我的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"];
}
答案 1 :(得分:5)
我遇到了完全相同的问题,并使用了与@entropid相同的代码。然而,接受的解决方案对我不起作用。
花了我几个小时的时间来提出以下一线解决方案,让事情对我有用:
- (void)viewWillLayoutSubviews {
[[UIApplication sharedApplication] setStatusBarHidden:NO withAnimation:UIStatusBarAnimationNone];
}
答案 2 :(得分:4)
昨天我遇到了这个问题,其中@entropid的答案适用于iOS 9及以下,但对于iOS 10它没有(因为iOS 10确实隐藏了状态栏,在iOS 9及以下它只是{ {1}}改变了它的框架而没有隐藏状态栏,因此,它与该栏重叠。
此外,订阅UINavigationBar
通知也不起作用,有时它根本就没有被调用(在我的特定情况下,这是因为它是来自MPMoviePlayerControllerDidExitFullScreen
的视频,它使用了不同类型的玩家,看起来类似于UIWebView
)。
所以我使用类似@StanislavPankevich建议的解决方案来解决它,但是当MPMoviePlayerController
被隐藏时我订阅了通知(这可能在几种情况下,就像视频结束时一样,但也是在UIWindow
解散和其他情况)而不是UIActivityViewController
。对于我的特定情况(viewWillLayoutSubviews
的子类),UINavigationController
,viewDidAppear
等方法根本没有被调用。
<强> viewDidLoad中强>
viewWillAppear
<强>的dealloc 强>
- (void)viewDidLoad {
[super viewDidLoad];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(videoDidExitFullscreen:)
name:UIWindowDidBecomeHiddenNotification
object:nil];
// Some other logic...
}
最后, videoDidExitFullscreen
- (void)dealloc {
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
我使用- (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
更平滑,至少从用户的角度来看。
答案 3 :(得分:3)
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)
}
答案 4 :(得分:1)
这很简单,正如@Stanislav Pankevich所说,但是
swift 3版
override func viewWillLayoutSubviews() {
super.viewWillLayoutSubviews();
UIApplication.shared.isStatusBarHidden = false
}
答案 5 :(得分: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};
}
}];
我没有正确测试它,但它现在正在为我工作
答案 6 :(得分: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;
}
这并未改变iOS 10及更低版本上的AVFullScreenViewController的行为,但修复了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上,对于其他设备则不需要。
答案 7 :(得分:-1)
我对这个问题的回答很有效。 Here它会正常播放您的WebView中的视频,但如果您倾斜手机,它将在Landscape中播放!
另外需要注意的是,如果您将youtube.com作为基本网址加入,它的加载速度会更快。
在故事板中创建一个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"]];