I have two views one of them is the mainVideoView (Grey color) and the other is the subVideoView (red color). Both of them are the subViews of UIApplication.shared.keyWindow
.
When I try and minimise them (using func minimiseOrMaximiseViews
, they get minimised (as shown in the below image).
After which, I would like to remove the subVideoView from the window. The moment I try and remove the subVideoView (using func removeSubVideoViewFromVideoView()
called from func minimiseOrMaximiseViews
), the mainVideoView enlarges to the full screen size, I am not sure why this is happening, I want it to stay at the same size.
Could someone please advise/ suggest how I could achieve this ?
This is how I am setting up the views
func configureVideoView(){
videoView.backgroundColor = UIColor.darkGray
videoView.tag = 0 // To identify view during animation
// ADDING TAP GESTURE TO MAXIMISE THE VIEW WHEN ITS SMALL
let tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(handleTap(gestureRecognizer:)))
videoView.addGestureRecognizer(tapGestureRecognizer)
// ADDING PAN GESTURE RECOGNISER TO MAKE VIDEOVIEW MOVABLE INSIDE PARENT VIEW
videoView.addGestureRecognizer(UIPanGestureRecognizer(target: self, action: #selector(self.dragView)))
guard let window = UIApplication.shared.keyWindow else{
return
}
window.addSubview(videoView)
videoView.translatesAutoresizingMaskIntoConstraints = false
let viewsDict = ["videoView" : videoView] as [String : Any]
// SETTING CONSTRAINTS
window.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "H:|[videoView]|", options: [], metrics: nil, views: viewsDict))
window.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "V:|[videoView]|", options: [], metrics: nil, views: viewsDict))
window.layoutIfNeeded() // Lays out subviews immediately
window.bringSubview(toFront: videoView) // To bring subView to front
print("Videoview constraints in configureVideoView \(videoView.constraints)")
}
func configureSubVideoView(){
subVideoView.backgroundColor = UIColor.red
subVideoView.tag = 1 // To identify view during animation
subVideoView.isHidden = true
// Adding Pan Gesture recogniser to make subVideoView movable inside parentview
subVideoView.addGestureRecognizer(UIPanGestureRecognizer(target: self, action: #selector(self.dragView)))
// Constraining subVideoView to window to ensure that minimising and maximising animation works properly
constrainSubVideoViewToWindow()
}
func constrainSubVideoViewToWindow(){
//self.subVideoView.setNeedsLayout()
guard let window = UIApplication.shared.keyWindow else{
print("Window does not exist")
return
}
guard !window.subviews.contains(subVideoView)else{ // Does not allow to go through the below code if the window already contains subVideoView
return
}
if self.videoView.subviews.contains(subVideoView){ // If videoView contains subVideoView remove subVideoView
subVideoView.removeFromSuperview()
}
window.addSubview(subVideoView)
// Default constraints to ensure that the subVideoView is initialised with maxSubVideoViewWidth & maxSubVideoViewHeight and is positioned above buttons
let bottomOffset = buttonDiameter + buttonStackViewBottomPadding + padding
subVideoView.translatesAutoresizingMaskIntoConstraints = false
let widthConstraint = NSLayoutConstraint(item: subVideoView, attribute: .width, relatedBy: .equal, toItem: nil, attribute: NSLayoutAttribute.notAnAttribute, multiplier: 1.0, constant: maxSubVideoViewWidth)
let heightConstraint = NSLayoutConstraint(item: subVideoView, attribute: .height, relatedBy: .equal, toItem: nil, attribute: NSLayoutAttribute.notAnAttribute, multiplier: 1.0, constant: maxSubVideoViewHeight)
let rightConstraint = NSLayoutConstraint(item: subVideoView, attribute: .trailing, relatedBy: .equal, toItem: window, attribute: .trailing, multiplier: 1.0, constant: -padding)
let bottomConstraint = NSLayoutConstraint(item: subVideoView, attribute: .bottom, relatedBy: .equal, toItem: window, attribute: .bottom, multiplier: 1.0, constant: -bottomOffset)
var constraintsArray = [NSLayoutConstraint]()
constraintsArray.append(widthConstraint)
constraintsArray.append(heightConstraint)
constraintsArray.append(rightConstraint)
constraintsArray.append(bottomConstraint)
window.addConstraints(constraintsArray)
window.layoutIfNeeded() // Lays out subviews immediately
subVideoView.setViewCornerRadius()
window.bringSubview(toFront: subVideoView) // To bring subView to front
}
This is how I am animating views and removing subVideoView
func minimiseOrMaximiseViews(animationType: String){
let window = UIApplication.shared.keyWindow
let buttonStackViewHeight = buttonsStackView.frame.height
if animationType == "maximiseView" {
constrainSubVideoViewToWindow()
}
UIView.animate(withDuration: 0.3, delay: 0, options: [],
animations: { [unowned self] in // "[unowned self] in" added to avoid strong reference cycles,
switch animationType {
case "minimiseView" :
self.hideControls()
// Minimising self i.e videoView
self.videoView.frame = CGRect(x: self.mainScreenWidth - self.videoViewWidth - self.padding,
y: self.mainScreenHeight - self.videoViewHeight - self.padding,
width: self.videoViewWidth,
height: self.videoViewHeight)
// Minimising subVideoView
self.subVideoView.frame = CGRect(x: self.mainScreenWidth - self.minSubVideoViewWidth - self.padding * 2,
y: self.mainScreenHeight - self.minSubVideoViewHeight - self.padding * 2,
width: self.minSubVideoViewWidth,
height: self.minSubVideoViewHeight)
window?.layoutIfNeeded()
self.videoView.setViewCornerRadius()
self.subVideoView.setViewCornerRadius()
print("self.subVideoView.frame AFTER setting: \(self.subVideoView.frame)")
default:
break
}
}) { [unowned self] (finished: Bool) in // This will be called when the animation completes, and its finished value will be true
if animationType == "minimiseView" {
// **** Removing subVideoView from videoView ****
self.removeSubVideoViewFromVideoView()
}
}
}
func removeSubVideoViewFromVideoView(){
//self.subVideoView.setNeedsLayout()
guard let window = UIApplication.shared.keyWindow else{
return
}
guard !self.videoView.subviews.contains(subVideoView)else{ // Does not allow to go through the below code if the videoView already contains subVideoView
return
}
if window.subviews.contains(subVideoView) { // removing subVideoView from window
subVideoView.removeFromSuperview() // *** CAUSE OF ISSUE ***
}
guard !window.subviews.contains(subVideoView) else{
return
}
videoView.addSubview(subVideoView)
}
The videoView and subVideoView are layout by Auto Layout. In Auto Layout if you want to change the frame, you have to update the constraints.
Calling
removeFromSuperView
will removes any constraints that refer to the view you are removing, or that refer to any view in the subtree of the view you are removing. This means the auto layout system will to rearrange views.