当删除 window 的子视图之一时,视图大小自动设置为 window 大小

View size is automatically being set to window size, when one of window's subview is removed

我有两个视图,一个是 mainVideoView(灰色),另一个是 subVideoView(红色)。它们都是UIApplication.shared.keyWindow的子View。

当我尝试最小化它们时(使用 func minimiseOrMaximiseViews,它们被最小化了(如下图所示)。

之后,我想从 window 中删除 subVideoView。当我尝试删除 subVideoView(使用从 func minimiseOrMaximiseViews 调用的 func removeSubVideoViewFromVideoView())时,mainVideoView 放大到全屏尺寸,我不确定为什么会这样,我希望它保持不变尺寸。

有人可以建议/建议我如何实现这一目标吗?

这就是我设置视图的方式

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

}

这就是我制作动画视图和删除 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)
}

videoView和subVideoView是自动布局的。在 Auto Layout 中,如果你想改变框架,你必须更新约束。

调用 removeFromSuperView 将删除任何引用您要删除的视图的约束,或引用您要删除的视图的子树中的任何视图的约束。这意味着自动布局系统将重新排列视图。