Reputation: 2168
I have a WKWebView
in my UIViewController
and I'm embedding a youtube video (using an iFrame) into the html along with text. When I launch the video it performs as intended, it opens in full screen, I can rotate either landscape orientations, plays fine etc. The problem lies when I close the video. My application is locked to portrait and when returning from the video the application is half black screen, half my application and the view that is still half my application looks to be in landscape (too larger for the width).
My application is locked portrait within the Info.plist
for the whole application. I am fine with the video rotating it just causes this interesting outcome.
1. Launch WKWebView with youtube iframe
2. Click to launch video (video plays full screen)
3. Rotate device to either landscape rotations.
4. Close the player
This is where you notice that half the application is black and the other half looks to be portrait orientation in landscape layout.
When I inspect the views before and after it mimics as if the app has rotated to landscape mode but the device is in portrait. (View starts at 414x862. After viewing and rotating with the video and returning to the view it shows as 862x414)
I'm not really sure what's going on here. Thoughts?
Thanks in advance
Upvotes: 2
Views: 648
Reputation: 2168
I was able to find a workaround/hack/solution to this. I kept my application locked to portrait but overrode the AppDelegate method for allowed orientations.
class AppDelegate: UIResponder, UIApplicationDelegate {
...
func application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask {
return OrientationManager.allowedOrientations
}
...
}
I created an OrientationManager
which was just a helper class to allow me to force rotations and alter the allowed orientations.
class OrientationManager {
/// The currently allowed orientations of the application (default: .portrait)
static var allowedOrientations: UIInterfaceOrientationMask = .portrait
/**
* Method to force the current orientation of the device.
*
* - Parameter orientation: The orientation to change to.
*
* - Warning: This method uses setValue(_, forKey:) which accesses values that may change in the future
*/
static func forceOrientation(_ orientation: UIInterfaceOrientation) {
let orientationRawValue = orientation.rawValue
UIDevice.current.setValue(orientationRawValue, forKey: "orientation")
UINavigationController.attemptRotationToDeviceOrientation()
}
}
The last thing I needed to do was figure out when the video was going in and out of full screen. I found some notifications that seemed to reliably fire when the video goes in and out of full screen. When this happens I enable the ability for the view to rotate, which allows it to go to Landscape behind the full screen video. Once the video is closed my view is now (unfortunately) showing in landscape which I can then force the orientation and re-lock it to portrait.
In the UIViewController
with the webview:
class WebViewWithVideoViewController: UIViewController {
...
// MARK: Properties
var videoDidFullScreenNotification: NSObjectProtocol?
var videoDidMinimizeNotification: NSObjectProtocol?
...
// MARK: Lifecycle
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
self.beginObserving()
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
self.endObserving()
}
// MARK: Observers
func beginObserving() {
// This is a solution to the video causing a half black screen when the device is rotated to landscape.
// The outline of the solution is that when the video is put into full screen mode, we update the
// available orientations to include both landscape directions. Upon the video being closed,
// we force the device orientation back to portrait and then lock it back to portrait only.
// This seems to work because the UIViewController is actually in landscape once complete
// and then it animates back to the portrait orientation and seems to keep the proper ratios
// and sizes.
if self.videoDidFullScreenNotification == nil {
self.videoDidFullScreenNotification = NotificationCenter.default.addObserver(
forName: UIWindow.didBecomeVisibleNotification,
object: self.view.window,
queue: nil
) { notification in
OrientationManager.allowedOrientations = .allButUpsideDown
}
}
if self.videoDidMinimizeNotification == nil {
self.videoDidMinimizeNotification = NotificationCenter.default.addObserver(
forName: UIWindow.didBecomeHiddenNotification,
object: self.view.window,
queue: nil
) { notification in
OrientationManager.forceOrientation(.portrait)
OrientationManager.allowedOrientations = .portrait
}
}
}
func endObserving() {
if let videoDidFullScreenNotification = self.videoDidFullScreenNotification {
NotificationCenter.default.removeObserver(videoDidFullScreenNotification)
}
if let videoDidMinimizeNotification = self.videoDidMinimizeNotification {
NotificationCenter.default.removeObserver(videoDidMinimizeNotification)
}
}
...
}
This seemed to have solved the screen showing half black after going in and out of full screen with embedded videos. Unfortunately there is a slight animation when you return from the full screen video, but it's a small sacrifice for a very weird bug.
Hope this helps anyone else with this (or similar issues) and happy coding!
Upvotes: 1