Pertanyaan Izinkan video pada lanskap dengan aplikasi potret saja


Saya memiliki UIWebView yang termasuk dalam UIViewController yang merupakan keturunan dari UINavigationController. Terlihat seperti ini:

Main view

Aplikasi ini hanya potret. Ketika saya memutar video saya ingin pengguna dapat memutar perangkat dan melihat video dalam mode lansekap. Saya menggunakan kode ini untuk mengizinkannya:

- (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;
}

Dan kemudian di UINavigationController saya (jadi ketika video selesai, tampilan tidak disajikan dalam lanskap tetapi hanya dalam potret):

- (BOOL)shouldAutorotate
{
    return NO;
}

- (NSUInteger)supportedInterfaceOrientations
{
    return UIInterfaceOrientationMaskPortrait;
}

- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation
{
    return UIInterfaceOrientationPortrait;
}

Semuanya bekerja dengan sempurna:

Video portrait  Video landscape

Tetapi kemudian video selesai diputar (atau pengguna mengetuk ‘Selesai’) dan layar kembali ke tampilan yang mendasarinya, inilah yang terjadi:

Navigation bar issue

Seperti yang Anda lihat, bilah navigasi tergelincir di bawah bilah status. Selain itu, saya mendapatkan banyak kesalahan tata letak otomatis di log: http://pastebin.com/09xHzmgJ

Ada gagasan tentang cara menyelesaikan ini?


32
2017-10-27 23:58


asal


Jawaban:


Saya sementara dipecahkan (melalui meretas) dengan kode berikut di viewDidLoad dari pengontrol saya. Saya harus menentukan bahwa kode dibuat khusus untuk kasus saya: karena saya secara eksplisit melarang orientasi lanskap UINavigationController saya (lihat kode di atas), pemberitahuan biasa "UIDeviceOrientationDidChange" tidak dipanggil saat pemutaran selesai dan jendela kembali ke potret. Namun, saya harap ada opsi yang lebih baik dan ini adalah bug dari SDK, karena tidak muncul di iOS 7 dan mengingat jumlah kesalahan tata letak otomatis yang saya dapatkan terkait dengan pemutar video (di mana saya tidak memiliki kontrol) .

- (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};
        }
    }];
}

Lalu…

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

17
2017-10-28 21:25



Saya mengalami masalah yang persis sama dan menggunakan kode yang sama dengan @entropid. Namun solusi yang diterima tidak berhasil untuk saya.

Butuh waktu berjam-jam untuk membuat perbaikan satu baris berikut yang membuat semuanya bekerja untuk saya:

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

5
2018-01-14 13:20



Saya menghadapi masalah ini kemarin, di mana jawaban @entropid berfungsi untuk iOS 9 dan di bawah, tetapi untuk iOS 10 tidak (sejak iOS 10 benar-benar menyembunyikan bilah status, di mana pada iOS 9 dan di bawahnya hanya UINavigationBar yang mengubah bingkai tanpa menyembunyikan bilah status dan, dengan demikian, itu tumpang tindih bar itu).

Juga, berlangganan MPMoviePlayerControllerDidExitFullScreen pemberitahuan tidak berhasil, kadang-kadang itu tidak disebut (dalam kasus khusus saya, itu karena itu adalah video dari a UIWebView, yang menggunakan kelas pemain berbeda yang terlihat mirip MPMoviePlayerController).

Jadi saya memecahkannya menggunakan solusi seperti yang disarankan @StanislavPankevich, tapi saya berlangganan notifikasi ketika UIWindow telah menjadi tersembunyi (yang bisa dalam beberapa kasus, seperti saat video selesai, tetapi juga ketika a UIActivityViewController memberhentikan dan kasus lain) bukannya viewWillLayoutSubviews. Untuk kasus khusus saya (subkelas dari UINavigationController), metode seperti viewDidAppear, viewWillAppear, dll hanya tidak dipanggil.

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];
}

Dan akhirnya, 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];

}

Saya menggunakan UIStatusBarAnimationFade karena terlihat jauh lebih halus daripada UIStatusBarAnimationNone, setidaknya dari perspektif pengguna.


4
2017-11-24 13:34



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

3
2018-05-21 14:41



Ini sangat sederhana, seperti yang dikatakan @Stanislav Pankevich, tetapi di

3 versi cepat

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

1
2017-11-30 11:50



Saya mengalami masalah yang sama dan menggunakan solusi @entropid saya dapat memperbaiki masalah bilah navigasi. Tapi pandangan saya tetap di bawah bilah nav yang saya perbaiki menggunakan "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};
    }
}];

Saya belum mengujinya dengan benar tetapi sekarang bekerja untuk saya


0
2018-03-09 13:18



Di iOS 11, solusi yang diterima tidak bekerja untuk saya. Sepertinya bilah navigasi berhenti mencerminkan untuk perubahan bingkai. Tetapi ada solusi. Pada awalnya, kita perlu memodifikasi supportedInterfaceOrientationsForWindow metode untuk kembali UIInterfaceOrientationMaskLandscape untuk pengontrol video, bukan UIInterfaceOrientationMaskAllButUpsideDown. Dalam kasus saya ketika saya mengetuk video YouTube yang tertanam, sistem selalu membuka AVFullScreenViewController, jadi saya menghapus cek lain dari contoh asli. Kode:

- (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;
}

Ini tidak mengubah perilaku AVFullScreenViewController pada iOS 10 dan kurang, tetapi memperbaiki bilah navigasi di iOS 11, sehingga tidak perlu memperbarui bingkai (juga ada efek samping pada iOS 11 bahwa video berputar dari lanskap ketika mulai diputar, tapi itu tradeoff). Selanjutnya, kita perlu menambahkan check in UIWindowDidBecomeHiddenNotification metode:

- (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);
    }
}

Tanpa setNeedsStatusBarAppearanceUpdate teks di status bar tidak akan muncul di iPhone X, karena perangkat lain tidak diperlukan.


0
2017-11-16 15:53



Jawaban saya atas pertanyaan ini sangat bagus. Sini Ini akan memutar video di dalam WebView Anda secara normal tetapi jika Anda memiringkan ponsel Anda akan bermain di Landscape!

Yang juga penting untuk diperhatikan adalah jika Anda memasukkan youtube.com sebagai URL Dasar, URL akan memuat lebih cepat.

Buat UIWebView di storyboard Anda dan hubungkan @property ke situ, lalu referensi di bawah.

    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"]];

-1
2018-02-23 19:04