nested AVPlayer fullscreen? - ios

I have an AVPlayer that's inside collectionview cell, that's inside a UICollectionView, that's located inside a collectionview cell.
I wanted to animate the AVPlayers frame to fit the entire screen, essentially a full screen transition however because of the hierarchy I'm having trouble accessing the main collectionview keywindow...
This is the code I am using so far in an attempt to access the full screens bounds.
let window = UIApplication.shared.keyWindow!
let v = UIView(frame: CGRect(x: -(window.frame.origin.x), y: (window.frame.origin.y) / 2, width: (window.frame.width) / 2, height: (window.frame.height) / 2 ))
UIView.animate(withDuration: 1, delay: 0, options: UIViewAnimationOptions.curveEaseOut, animations: {
self.playerView?.bounds = v.bounds
self.layoutIfNeeded()
}, completion: { (completed) in
})
What this currently does is mask playerView to the bounds of the nested collectionView in the cell. Which leads me to believe because of how the hierarchy is that method might not be feasible.
I was hoping that there would be some method like AVPlayer.fullscreen() or something because I know it is possible to get fullscreen video using AVPlayerControllers overlay view but I don't want the user to have to press a button to go fullscreen. I prefer my current method of just tapping the video.
Any suggesetions?

You need to use an AVPlayerLayer this layer is the one that is going to be added as a sublayer to the view you want.
In this case first you need to add a UIView to your collectionViewCell and add your AVPlayerLayer instance as a sublayer.
When the user tap on the cell you must first remove AVPlayerLayer from the cell and pass the reference to your Root view controller in there you can add a new UIView of the size of the entire screen and add the AVPlayerLayer as a sublayer of that view.
Keep in mind that if you have a navigation controller you should add that UIView as a subview of the navigation controller and if you have a tabBar you need to add it to the tabBar insted.
To return from "Full screen" mode you do the oposite.

Related

View Reloads When Frame is Changed

I have a YouTubePlayer (from here) in my app. I have a UIViewController (we'll call this MainViewController) with a UITableView full of videos. Whenever a user taps on a cell, it opens another UIViewController (we'll call this DetailViewController) with my custom xib view called playerView. Like I said, playerView is a custom xib view and in that view is my YouTubePlayer. This is how I set up playerView in my DetailViewController
playerContainer.addSubview(playerView)
playerView.frame = CGRect(x: 0, y: 0, width: playerContainer.frame.size.width , height: playerContainer.frame.size.height)
playerView.player.loadVideoID(nowPlayingVideo.id)
Ok so this works great. BUT... whenever the user dismisses DetailViewController, I want playerView to be moved to the MainViewController. Like where the user can see what is playing in the background. So to do this, I added this code in DetailViewController...
override func viewWillDisappear(_ animated: Bool) {
nowPlayingView.addSubview(playerView)
playerView.frame = CGRect(x: 8, y: 8, width: width, height: height)
playerView.layoutIfNeeded()
}
nowPlayingView is another custom xib view and is added to the app's window earlier on. So this is where I start running into problems. This code works great. The frame is changed correctly and it's added to nowPlayingView, but, the YouTubePlayer in playerView seems to reload. So it pauses playback, shows a loading icon, and then resumes. It's pretty annoying. This shouldn't be happening because the video is already loaded in the YouTubePlayer. I'm pretty sure it happens only whenver I am changing the frame of playerView. Does anyone have any ideas on how to fix this?
When the video resumes playing after loading, does the video start over or does it resume where it left off before changing the view?

How to create a segue to slide in and fade in at the same time (Xcode 9, Swift 4)

I'm trying to create a custom segue which slides in from the right and slides out (like the default Push segue) but also fades in/out as it slides in/out. I think I've figured out the fading code for transitioning to the destination view controller but can't figure out how to make the view slide in from the left and slide out to the right. I thought this would have something to do with the trailing and leading constraints of the view but I'm not really sure how to reference those constraints in my custom segue class. I know you can connect constraints to the code using IBOutlets for specific view controllers but I want to use this same custom segue class for custom segues across all my view controllers.
I was also wondering how to make the segue refer to the unwind segue class to go from the destination view controller to the source view controller. For example, when I click on the segue in the storyboard, in the "class" text field, I put the class name for the segue which transitions to the destination view controller but where would I do the same for the unwind segue so that when I click back, it also performs the custom segue to go back to the source view controller.
This is the code I've done so far for the segue which transitions to the destination view controller (haven't started on the unwind segue yet but I imagine it would be pretty much the same). Near the bottom of the class, I started trying out the anchor properties but they didn't work. Thanks!
class DimSegue: UIStoryboardSegue {
override func perform() {
// Get the view of the source
let sourceViewControllerView = self.source.view
// Get the view of the destination
let destinationViewControllerView = self.destination.view
let screenWidth = UIScreen.main.bounds.size.width
let screenHeight = UIScreen.main.bounds.size.height
// Make the destination view the size of the screen
destinationViewControllerView?.frame = CGRect(x: 0, y: 0, width: screenWidth, height: screenHeight)
// Insert destination below the source
// Without this line the animation works but the transition is not smooth as it jumps from white to the new view controller
destinationViewControllerView?.alpha = 0;
sourceViewControllerView?.addSubview(destinationViewControllerView!);
let margins = destinationViewControllerView?.superview?.layoutMarginsGuide
// Animate the fade, remove the destination view on completion and present the full view controller
UIView.animate(withDuration: 1, delay: 0, options: .curveLinear, animations: {
destinationViewControllerView?.leadingAnchor.constraint(equalTo: (margins?.leadingAnchor)!, constant: 1000)
destinationViewControllerView?.trailingAnchor.constraint(equalTo: (margins?.trailingAnchor)!, constant: 1000)
destinationViewControllerView?.layoutIfNeeded()
destinationViewControllerView?.alpha = 1
}, completion: nil )
}
}

How to properly create an overlay view in storyboard?

My aim is to create a popup view right below a button once is clicked, this is the concept:
The way I prepared the storyboard is by using two different UIViewController. The main one contains the two buttons and, once clicked, I modally push the second UIViewController over the current context.
My question is: what's the best or properly way to create constrain in order to move the "Tapped" image right below the button?
The way I do this is to add a childcontroller to your first storyboard vc. Then adjust the frame of the container view in the storyboard, which I hope will be easier than programmatically adjusting frames.
Then be sure to change the class on top of the VC that Xcode created for you.
When the button is clicked get the the bottom position of it (it's y in frame + height) and send it to the popup , then set them as the top constraint of the imageView in popup in viewDidLayoutSubview
You can calculate the position of the overlay using the button's and the view's positions and dimensions. For example, the overlay's y can be the button's frame.maxY + constant.
let x = ...
let y = ...
let width = ...
let height = ...
let overlay = UIView(frame: CGRect(x: x, y: y, width: width, height: height))
view.addSubView(overlay)
The translucent black view can be added as a UIView with the same frame as the view of the VC and constrained to always be the same as the frame of the VC's view. Add this view first, before you add overlay.

UIView Transition in table view

I want to do transition of a view inside a table view cell. More precisely, when user clicks on a button in UITableViewCell a view should slide in from the right side of the cell and this view should slide back to its original position when user clicks on a button in the slided view. I could do all of this except the animation of sending the slided view back to its original position.
To accomplish this what I have done so far is, created a xib file for the table view cell which contains two views side by side, let it be view1 and view2. When the tableview is loaded to screen, only view1 is visible to the user. And set auto layout constraint for view1.trailingedge and view2.leadingedge as 0, the constraint is connected to cell.swift and named leftConstraint. Now when a button in view1 is clicked view2 slides in from the right side of the cell using the following code :-
self.view2.transform = CGAffineTransformMakeTranslation(UIScreen.mainScreen().bounds.width, 0)
UIView.animateWithDuration(0.4, animations: { () -> Void in
self.view2.transform = CGAffineTransformIdentity
self.leftConstraint.constant -= UIScreen.mainScreen().bounds.width
})
When tried to send back view2 to its old position (this should happen on the click of a button in view2) ie. right side of the cell animation is not working, all the elements in view2 just disappears. Using the following code for sending view to the right side of the cell:-
self.view2.transform = CGAffineTransformMakeTranslation(UIScreen.mainScreen().bounds.width, 0)
UIView.animateWithDuration(0.4, animations: { () -> Void in
self.view2.transform = CGAffineTransformIdentity
self.leftConstraint.constant += UIScreen.mainScreen().bounds.width
})
Thanks in Advance for any help. And special Thanks to #MarkHim for helping.
Since you need the transformation for the rightOut position twice, first for the in-animation and later for the out animation, you could save it in a variable like rightOutTransform. Try:
CGAffineTransform rightOutTransform = CGAffineTransformMakeTranslation(self.view.fame.size.width, 0);
// assuming view2 is currently in the cell
UIView.animateWithDuration(0.4, animations: {
self.view2.transform = rightOutTransform //
})
You might want to think about removing views you don't need anymore from the view hierarchy like this when the animation completed
view2.removeFromSuperview();

iPhone, iOS 8: How to presentViewController smaller than original view controller?

I have two view controllers, I want to present view controller(VC) of the first VC. Second VC have smaller size. I want to show second view controller over the first one. Like a popover. You can imagine it, if we add another view controller that slides from bottom to top but stops at navigation bar.
Here is my code:
#IBAction func showSecondVC(sender: AnyObject) {
let secondViewController = storyboard?.instantiateViewControllerWithIdentifier("SecondViewController") as! SecondViewController
secondViewController.view.frame = CGRect(origin: CGPoint(x: view.frame.origin.x, y: header.frame.height), size: CGSize(width: view.frame.width, height: view.frame.height - header.frame.height))
secondViewController.definesPresentationContext = true
secondViewController.providesPresentationContextTransitionStyle = true
secondViewController.modalPresentationStyle = UIModalPresentationStyle.CurrentContext
self.presentViewController(secondViewController, animated: true, completion:nil)
}
You can see that I set frame for secondViewController. I want that it will be with this frame, but if I add completion block and show it's frame after animation, it will be same as first View Controller have.
Edit
I also want to mention, that I try to make this in Portrait orientation.
If you try this in iPhone, the built-in root view of presented view controller will always be full screen, so your efforts to resize it will not be successful. (iPad is a different story)
Just let the root view as it is (i.e. don't fight the fact it's full screen size ), but make its background color clear color. If you want to present some kind of customised view/content/whatever it is..for example a smaller view with some warning..or some options. Just add it as a subview of the root view.
UPDATE:
As the UIViewController class documentation says:
"In a horizontally compact environment, the presented view is always full screen."
The only combination I can imagine for this to work is Iphone6+ in landscape mode where the horizontal size class is then larger then compact. So you are out of luck because you want portrait.
To add the Earl Grey's response, after setting the ViewController's background color to clear. Create a segue with the following properties set:
Kind to "Present Modally"
Presentation to "Over Current Context"

Resources