Closed rehannali closed 7 years ago
Hi @rehannali,
Right now the video player changes from portrait to landscape when the ViewController changes orientation.
If you want to force it to be in Landscape in a Portrait only app, you can set up constraints for all 4 edges and use the following code in viewDidLoad()
:
//videoPlayer is an instance of ASPVideoPlayer positioned within the view of a ViewController
//view is the view of the ViewController
videoPlayer.transform = CGAffineTransform(rotationAngle: .pi / 2.0)
let padding = (view.bounds.height - view.bounds.width) / 2.0
rightConstraint.constant = -padding
leftConstraint.constant = -padding
topConstraint.constant = padding
bottomConstraint.constant = padding
view.layoutIfNeeded()
Orientation and layout changes should ideally be handled by your app, this way you can create whatever layout configuration and animation transition you like.
I will probably create a button for this in the UI and provide a closure that you can use to specify your own rotation logic.
Hi @andreipitis Actually, I want like Youtube manual rotation i.e. When I pressed a button in little screen it forced player to rotate the view in full-screen mode automatically. That's why I need this to perform custom player. If this is possible now, can you please tell me how i can do it?
There is no builtin functionality for this, but as I said in my previous comment, you can implement that functionality yourself. There is no button to tap, but you could either implement your own UI (just copy the code for ASPVideoPlayerControls
and add that button, or subclass ASPBasicControls
and implement your custom UI with buttons, slider, etc.), or just use some kind of gesture to start the animation.
In the future I will add a button to the existing UI, but the rotation functionality will not be performed automatically. As I said before, the users of the component should implement their own rotation/fullscreen functionality because I can't know what kind of layout everyone has and this way everyone can create the exact layout and animation that fits their needs.
Thank you for creating this wonderful library. can you please provide the full code how to make the videoPlayer to streched all over the screen in horizontal (even tho the app is portrait only) . the following line does work: videoPlayer.transform = CGAffineTransform(rotationAngle: .pi / 2.0) but how can I make it stretch all over the screen ? the constraint part is unclear. BTW my play is 100width and 100height, and when i click on some button i want to make it stretch all over the screen, only the stretching is my problem... thanks in advance.
Hi @moheny,
Unfortunately without knowing your exact layout I cannot provide the specific solution for your use case. I am assuming that you have a similar layout to this one:
In this case, the containerView
has a fixed height, and has a single child that fills the entire view (the videoPlayer
).
With the above layout the folowing code works:
var isExpanded: Bool = false
var previousConstraints: [NSLayoutConstraint] = []
func rotate() {
let views: [String:Any] = ["videoPlayer": videoPlayer]
if isExpanded == false {
UIView.animate(withDuration: 0.25, delay: 0.0, options: [], animations: {
self.containerView.removeConstraints(self.videoPlayer.constraints)
self.view.addSubview(self.videoPlayer)
let padding = (self.view.bounds.height - self.view.bounds.width) / 2.0
let metrics: [String:Any] = ["padding":padding, "negativePadding":-padding]
self.videoPlayer.transform = CGAffineTransform(rotationAngle: .pi / 2.0)
var constraints: [NSLayoutConstraint] = []
constraints.append(contentsOf: NSLayoutConstraint.constraints(withVisualFormat: "H:|-(negativePadding)-[videoPlayer]-(negativePadding)-|", options: [], metrics: metrics, views: views))
constraints.append(contentsOf: NSLayoutConstraint.constraints(withVisualFormat: "V:|-(padding)-[videoPlayer]-(padding)-|", options: [], metrics: metrics, views: views))
self.view.addConstraints(constraints)
self.view.layoutIfNeeded()
self.previousConstraints = constraints
}, completion: { finished in
self.isExpanded = true
})
} else {
UIView.animate(withDuration: 0.25, delay: 0.0, options: [], animations: {
self.view.removeConstraints(self.previousConstraints)
self.containerView.addSubview(self.videoPlayer)
self.videoPlayer.transform = CGAffineTransform(rotationAngle: 0.0)
var constraints: [NSLayoutConstraint] = []
constraints.append(contentsOf: NSLayoutConstraint.constraints(withVisualFormat: "H:|[videoPlayer]|", options: [], metrics: nil, views: views))
constraints.append(contentsOf: NSLayoutConstraint.constraints(withVisualFormat: "V:|[videoPlayer]|", options: [], metrics: nil, views: views))
self.containerView.addConstraints(constraints)
self.view.layoutIfNeeded()
self.previousConstraints = constraints
}, completion: { finished in
self.isExpanded = false
})
}
}
Obviously it's not the cleanest code, and there may be some better solutions to achieve this functionality depending on the layout you use. This is just a quick test that I came up with.
Basically the rotation only affects the visual representation of the player, the constraints are kept as if the player were not rotated at all. In order to get the desired result, you have to change the constraints so that the player gets centred and stretched in such a way that the height is equal to the width of the screen and the width of the player is equal to the height of the screen.
This is how the animation would look without the rotation code:
Thank you of much for taking your time and answer. The layout you have created is the exact layout i have, and i guess my problem is I didn't remove the constraint before I have tried to change it, i'll try to play with it and update you . BTW, I think it's easier using an library for the layout instead of writing it :-) something like snapKit it 5 times easier ..
Hey @andreipitis this post helped me a lot. Only issue I'm facing is on the iPhone X with the safe area. for some reason I cannot see why the controls I have as part of the videoPlayer
do not fit within the safe area. Do you have any suggestions for this? Many thanks.
Hi @kyazdani ,
So you have something like this:
And you want something like this:
I you want to achieve this, you just need to edit the code in the comment above for the rotate()
function.
Replace this:
let metrics: [String:Any] = ["padding":padding, "negativePadding":-padding]
with this:
var bottomPadding: CGFloat = 0
if #available(iOS 11.0, *) {
if self.view.safeAreaInsets != .zero {
bottomPadding = self.view.safeAreaInsets.bottom
}
}
let metrics: [String:Any] = ["padding":padding, "negativePadding":-(padding - bottomPadding)]
I may have misunderstood you, if this was not your issue could you please clarify what you want to achieve?
Hi @andreipitis, apologies I didn't see you reply. This works really well. However outside the safe area on your second screenshot you have a white section. I get this same section with this added code. Is there anything you would suggest for filling this bit in black without the rotation looking odd?
Also I'm getting some constraint errors when rotating. I think this is purely down to the setup of my nib. What constraints do you have applied to theContainer View
?
Many thanks :-)
@kyazdani the easiest way would be to just set the background color of the superview to black.
If that is not an option, you could add another subview with a black background in the containerView
so that it is a sibling of the videoPlayer
with the same constraints. Then you would simply add the same animations and constraints to that view with a slight modification: instead of setting the negative padding to be equal to -(padding - bottomPadding)
you would add a new metric for negative padding with the value -padding
so that it fills the entire screen.
The code for this method looks like this:
func rotate(isExpanded: Bool) {
let views: [String:Any] = ["videoPlayer": videoPlayer,
"backgroundView": videoPlayerBackgroundView]
var constraints: [NSLayoutConstraint] = []
if isExpanded == false {
self.containerView.removeConstraints(self.videoPlayer.constraints)
self.view.addSubview(self.videoPlayerBackgroundView)
self.view.addSubview(self.videoPlayer)
self.videoPlayer.frame = self.containerView.frame
self.videoPlayerBackgroundView.frame = self.containerView.frame
let padding = (self.view.bounds.height - self.view.bounds.width) / 2.0
var bottomPadding: CGFloat = 0
if #available(iOS 11.0, *) {
if self.view.safeAreaInsets != .zero {
bottomPadding = self.view.safeAreaInsets.bottom
}
}
let metrics: [String:Any] = ["padding":padding,
"negativePaddingAdjusted":-(padding - bottomPadding),
"negativePadding":-padding]
constraints.append(contentsOf:
NSLayoutConstraint.constraints(withVisualFormat: "H:|-(negativePaddingAdjusted)-[videoPlayer]-(negativePaddingAdjusted)-|",
options: [],
metrics: metrics,
views: views))
constraints.append(contentsOf:
NSLayoutConstraint.constraints(withVisualFormat: "V:|-(padding)-[videoPlayer]-(padding)-|",
options: [],
metrics: metrics,
views: views))
constraints.append(contentsOf:
NSLayoutConstraint.constraints(withVisualFormat: "H:|-(negativePadding)-[backgroundView]-(negativePadding)-|",
options: [],
metrics: metrics,
views: views))
constraints.append(contentsOf:
NSLayoutConstraint.constraints(withVisualFormat: "V:|-(padding)-[backgroundView]-(padding)-|",
options: [],
metrics: metrics,
views: views))
self.view.addConstraints(constraints)
} else {
self.view.removeConstraints(self.previousConstraints)
let targetVideoPlayerFrame = self.view.convert(self.videoPlayer.frame, to: self.containerView)
let targetVideoPlayerBackgroundViewFrame = self.view.convert(self.videoPlayerBackgroundView.frame, to: self.containerView)
self.containerView.addSubview(self.videoPlayerBackgroundView)
self.containerView.addSubview(self.videoPlayer)
self.videoPlayer.frame = targetVideoPlayerFrame
self.videoPlayerBackgroundView.frame = targetVideoPlayerBackgroundViewFrame
constraints.append(contentsOf:
NSLayoutConstraint.constraints(withVisualFormat: "H:|[videoPlayer]|",
options: [],
metrics: nil,
views: views))
constraints.append(contentsOf:
NSLayoutConstraint.constraints(withVisualFormat: "V:|[videoPlayer]|",
options: [],
metrics: nil,
views: views))
constraints.append(contentsOf:
NSLayoutConstraint.constraints(withVisualFormat: "H:|[backgroundView]|",
options: [],
metrics: nil,
views: views))
constraints.append(contentsOf:
NSLayoutConstraint.constraints(withVisualFormat: "V:|[backgroundView]|",
options: [],
metrics: nil,
views: views))
self.containerView.addConstraints(constraints)
}
self.previousConstraints = constraints
UIView.animate(withDuration: 2.25, delay: 0.0, options: [], animations: {
self.videoPlayer.transform = isExpanded == true ? .identity : CGAffineTransform(rotationAngle: .pi / 2.0)
self.videoPlayerBackgroundView.transform = isExpanded == true ? .identity : CGAffineTransform(rotationAngle: .pi / 2.0)
self.view.layoutIfNeeded()
})
}
There are probably better/cleaner ways to do this, but this is the first thing that came to mind.
For the constraints you can check the Main.storyboard
file of the example project, but it's all very simple: top, leading and trailing of the containerView
to the superview are 0 and it also has a fixed height of 300 in my example.
The above code should work even if you position the containerView
with an offset from the top.
Hi that's great. However the other problem presents itself with this method. How would you be able to make the video fit the full size of the phone? For example YouTube when you double tap the screen would increase the size of the video to full size but the controls would stay where they are.
With the existing implementation, you can't. You can however create your own controls, by subclassing ASPBasicControls
and setting the videoPlayerControls
property of ASPVideoPlayer
to use your custom class.
You could pretty much copy the implementation of ASPVideoPlayerControls
and adjust the layout code for iPhone X according to your needs.
There is no method related to Full-screen mode. There should be button simple at the bottom right corner so you should choose whether the fullscreen mode is portrait or landscape.
Please add this functionality or it you already added it and I don't know then sorry for my mistake and Could you please tell me whether this functionality is implemented or not?