Presenting UIView on AVPlayerViewController Fullscreen View - ios

Problem: I need to add a UIView on top of an AVPlayer in a way that it is still user-interactive. When I try to add it as Overlay Content, any user interactive button will not fire anymore (as it is behind the video control layer).
Desired effect: I'd like to be able to add an UIView on top of an AVPlayer so that it is kept on top of the whole view at all times even when it enters fullscreen mode.
Sample Code:
var view = UIView = {
let view = UIView()
view.frame = CGRect(x: 0, y: 0, width: 100, height: 100)
view.backgroundColor = .red
return view
}
var player = AVPlayer(url: http://somewhere.com/video.format)
let controller = AVPlayerViewController()
controller.player = player

Apparently, the best way to solve this issue was just adding a touchable element into the AVPlayerController, which redirected any touch event to the respective selector.

Related

AVPlayer get rid of black bars/background at top & bottom (Swift)

Quick question, does anybody know how i can get rid of the black bars at the top and bottom of my video? I just started using AVPlayer and i'm just removing codes here and there in attempt to remove the black layers. Appreciate those who can help me, Thanks!
UIViewController
import UIKit
import AVKit
import AVFoundation
private var looper: AVPlayerLooper?
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let path = Bundle.main.path(forResource: "Innie-Kiss", ofType:"mp4")
let player = AVQueuePlayer(url: URL(fileURLWithPath: path!))
looper = AVPlayerLooper(player: player, templateItem: AVPlayerItem(asset: AVAsset(url: URL(fileURLWithPath: path!))))
let controller = AVPlayerViewController()
controller.player = player
let screenSize = UIScreen.main.bounds.size
let videoFrame = CGRect(x: 0, y: 200, width: screenSize.width, height: (screenSize.height - 130) / 2)
controller.view.frame = videoFrame
self.view.addSubview(controller.view)
player.play()
}
}
You need to set the videoGravity of the AVLayer. The default value is .resizeAspect which will preserve the aspect ratio with black bars on top/bottom or left/right. What you want is .resize
The AVLayer you need to set the videoGravity on is the layer property of your AVPlayer.
see this for more info: https://developer.apple.com/documentation/avfoundation/avplayerlayer/1388915-videogravity
#import AVKit
var playerController = AVPlayerViewController()
playerController.videoGravity = .resizeAspect
/*playerController.videoGravity = .resizeAspectFill*/
playerController.view.backgroundColor = UIColor.white //set color as per super or custom view.
Note: If you set the videoGravity of the AVPlayerViewController. The default value is .resizeAspect then it is possible to visibility of black color(default) in background if you wants this color would similar to your super view's color then you must set superview's or custom view's color to your playercontroller's view background color.
*Example:Suppose super view's or custom view's background color is white then playerController view's background color must be set as playerController.view.backgroundColor = UIColor.white *
Note :playerController's backgroundColor should not be set as UIColor.white ,always. It must me set as super view' background color.
If you set playerController.videoGravity = .resizeAspectFill then it will fill the player content to super view or custom view, here also no black color would be shown. So choose either .resizeAspect or resizeAspectFill as per your requirements.

AVPlayerViewController inside a view is not showing the playback controls

I am working with apple tv. I have a UIView inside my UIViewController. I am adding AVPlayerViewController as subview of my UIView. UIView's frame is CGRect(x: 50, y: 50, width: 1344, height: 756). I am setting AVPlayerViewController frame equals to my UIView's frame.
Issue is that video plays fine in its frame but the controls like pause, play, forward etc. are hidden and not working. But when I set frame as CGRect(x: 0, y: 0, width: 1920, height: 1080), controls are visible and working.
My code is as per below:
let url = URL(string: "https://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4")
let item = AVPlayerItem(url: url!)
self.player = AVPlayer(playerItem: item)
self.avplayerController = AVPlayerViewController()
self.avplayerController.player = self.player
self.avplayerController.view.frame = videoPreviewLayer.frame
self.avplayerController.showsPlaybackControls = true
self.avplayerController.requiresLinearPlayback = true
self.addChildViewController(self.avplayerController)
self.view.addSubview(self.avplayerController.view)
self.avpController.player?.play()
Please help.
I managed to solve this using this code:
let player = AVPlayer(url: self.videoUrl!)
let avPlayerController = AVPlayerViewController()
avPlayerController.player = player;
avPlayerController.view.frame = self.videoPlayView.bounds;
self.addChildViewController(avPlayerController)
self.videoPlayView.addSubview(avPlayerController.view);
Now AVPlayerViewController shows most playback controls even as child to a uiview.
Courtesy:
https://www.techotopia.com/index.php/IOS_8_Video_Playback_using_AVPlayer_and_AVPlayerViewController
This is an expected behaviour:
AVPlayerViewController is designed such that when in full screen, the
full playback experience (scrubbing, info panel access, etc) are all
available. When in a space less than full screen, the assumption is
that it is just one of several interactive elements on screen, and
thus the view should not absorb all touch surface events as transport
control.
You can read more about this on this thread: https://forums.developer.apple.com/thread/19526

Set the ViewController on UIView programmatically

Is it possible to set the viewController for an UIView programmatically? What I want to do is make a UIView that always covers 50% of the screen's height and add a ViewController on that view after initializing it. I can't seem to find a method. Pseudocode:
let view = UIView(frame: CGRect(x: 0, y: 0, width: UIScreen.main.bounds.width, height UIScreen.main.bounds.height * 0.5)
//Can't seem to find a method that does exactly this:
view.setViewController(.......)
Insert yourAnotherVC.view as a subview to yourview
var MenuView: AnotherViewController? = (self.storyboard?.instantiateViewController(withIdentifier: "NewsView") as? AnotherViewController)
self.addChildViewController(MenuView)
MenuView?.didMove(toParentViewController: self)
MenuView?.view?.frame = CGRect(x: CGFloat(0.0), y: CGFloat(self.containerView.frame.size.height), width: CGFloat(self.containerView.frame.size.width), height: CGFloat(self.containerView.frame.size.height))
yourview.insertSubview(MenuView?.view, belowSubview: self.bottomMenuView)
//Show presentation logic here forward i mean show Anotherviewvc bottom to top or top to bottom
I'll hide and show views instead of switching out the whole UIViews so no more answers needed #close
// Add Child View Controller from your MainVC
addChildViewController(viewController) //your 2nd VC
// Add Child View as Subview
view.addSubview(viewController.view)
// Configure Child View
viewController.view.frame = view.bounds //here you make it 50% of height!
viewController.view.autoresizingMask = [.flexibleWidth, .flexibleHeight]
// Notify Child View Controller
viewController.didMove(toParentViewController: self)
You can add a Container View, that uses its own UIViewController. Simply drag it from the object library and you are good to go.

Bring Subview Above Everything But Below Another UIView

I am trying to place a UIView - popupView at the top, and another UIView (opaqueView) below popupView but above anything else. PopUpView is connected with an Outlet.
func display() {
popupView.center = CGPointMake(CGRectGetMidX(self.view.bounds), tableView.center.y);
self.view.addSubview(popupView)
popupView.clipsToBounds = true
let opaqueView = UIView()
let screenSize: CGRect = UIScreen.mainScreen().bounds
opaqueView.frame.size = CGSize(width: screenSize.width, height: screenSize.height)
opaqueView.alpha = 0.6
UIApplication.sharedApplication().keyWindow!.insertSubview(opaqueView, belowSubview: popupView)
}
Using this approach causes the opaqueView getting placed over everything including the popupView. Instead, I want to have popupView above opaqueView but keep opaqueView above everything else (view, TabBar, NavBar)
parent.insertSubview(child, belowSubview: sibling) works only when the sibling is a direct child of parent, so that child and sibling share the same parent. The current code does not work because opaqueView (the child) and popupView (the sbiling) have different parents.
That means either ① popupView should use the keyWindow as the parent, or ② opaqueView should use self.view as parent. Since you want opaqueView be above of everything, option ① is the only solution.

How to display UIView over keyboard in iOS

I want to create a simple view over keyboard, when users tap "Attach" button in inputAccessoryView.
Something like this:
Is there an easy way to do it? Or i should create my custom keyboard?
You can add that new subview to your application window.
func attach(sender : UIButton)
{
// Calculate and replace the frame according to your keyboard frame
var customView = UIView(frame: CGRect(x: 0, y: self.view.frame.size.height-300, width: self.view.frame.size.width, height: 300))
customView.backgroundColor = UIColor.redColor()
customView.layer.zPosition = CGFloat(MAXFLOAT)
var windowCount = UIApplication.sharedApplication().windows.count
UIApplication.sharedApplication().windows[windowCount-1].addSubview(customView);
}
Swift 4 version:
let customView = UIView(frame: CGRect(x: 0, y: self.view.frame.size.height - 300, width: self.view.frame.size.width, height: 300))
customView.backgroundColor = UIColor.red
customView.layer.zPosition = CGFloat(Float.greatestFiniteMagnitude)
UIApplication.shared.windows.last?.addSubview(customView)
The trick is to add the customView as a top subview to the UIWindow that holds the keyboard - and it happens to be the last window in UIApplication.shared.windows.
Swift 4.0
let customView = UIView(frame: CGRect(x: 0, y: self.view.frame.size.height-300, width: self.view.frame.size.width, height: 300))
customView.backgroundColor = UIColor.red
customView.layer.zPosition = CGFloat(MAXFLOAT)
let windowCount = UIApplication.shared.windows.count
UIApplication.shared.windows[windowCount-1].addSubview(customView)
As Tamás Sengel said, Apple's guidelines does not support adding a view over the keyboard. The recommended way to add a view over keyboard in Swift 4 & 5 is:
1) Add view with your "Next" button in your storyboard as external view and connect in your class (see Explain Image), in my case:
IBOutlet private weak var toolBar: UIView!
2) For the textfield you want to add your custom view over keyboard, add it as accessory view in viewDidLoad:
override func viewDidLoad() {
super.viewDidLoad()
phoneNumberTextField.inputAccessoryView = toolBar
}
3) Add action for "Next" button:
#IBAction func nextButtonPressed(_ sender: Any) {
descriptionTextView.becomeFirstResponder()
// or -> phoneNumberTextField.resignFirstResponder()
}
Explain Image:
Method 2: Result with image
In TableView Controller - add stricked view at bottom
Please follow this great link to handle safe area for screens like iPhone X if you want to use this method(2). Article: InputAccessoryView and iPhone X
override var inputAccessoryView: UIView? {
return toolBar
}
override var canBecomeFirstResponder: Bool {
return true
}
Do you have find some effective method to solve this problem? In iOS9,you put your customView on the top of the windows:
UIApplication.sharedApplication().windows[windowCount-1].addSubview(customView);
But if the keyboard dismisses, the top Windows will be removed, so your customView will be removed.
Looking forward for your help!
Thank you for your help!
You can definitely add the view to your application’s window, and you can also add another window entirely. You can set its frame and level. The level could be UIWindowLevelAlert.
While this can be possible with accessing the topmost window, I would avoid doing this, as it clearly interferes with Apple's guidelines.
What I would do is dismissing the keyboard and replacing its frame with a view with same dimensions.
The keyboard's frame can be accessed from keyboard notifications listed here, their userInfo contain a key that can be accessed with UIKeyboardFrameEndUserInfoKey.

Resources