代码之家  ›  专栏  ›  技术社区  ›  Minebomber

起伏的全屏退出过渡

  •  2
  • Minebomber  · 技术社区  · 8 年前

    我有一个自定义的视图控制器,可以通过一个按钮全屏显示。它通常是视图(嵌入)的子视图。我在embed的全屏输入是:

    private func enterFullScreenFromEmbed() {
    
        self.proxyView = UIView(frame: self.view.frame)
        self.proxyView?.isHidden = true
        self.proxyView?.autoresizingMask = self.view.autoresizingMask
        self.view.superview?.addSubview(self.proxyView!)
    
        // Now set the frame to the screen frame
        let frame = self.view.window?.convert(self.view.frame, from: self.proxyView?.superview)
        self.view.window?.addSubview(self.view)
        self.view.frame = frame!
    
        self.isFullscreen = true
    
        UIView.animate(withDuration: 0.25) { 
            self.view.frame = self.view.window!.bounds
            self.view.layoutIfNeeded()
            self.setNeedsStatusBarAppearanceUpdate()
        }
    }
    

    并退出全屏:

    private func exitFullScreenToEmbed() {
    
        let frame = self.view.window?.convert(self.view.frame, to: self.proxyView?.superview)
        self.proxyView?.superview?.addSubview(self.view)
        self.view.frame = frame!
    
        self.isFullscreen = false
    
        UIView.animate(withDuration: 0.25, animations: {
    
            self.view.frame = self.proxyView!.frame
    
            self.view.layoutIfNeeded()
            self.setNeedsStatusBarAppearanceUpdate()
        }) { (_) in
            self.proxyView?.removeFromSuperview()
            self.proxyView = nil
        }
    }
    

    这很好,除了我在进入全屏动画中隐藏状态栏,并在退出全屏动画中显示它。这会导致顶视图跳回原位,而不设置动画。

    isFullscreen 变量隐藏状态栏。

    override var prefersStatusBarHidden: Bool {
        return isFullscreen
    }
    
    override var preferredStatusBarUpdateAnimation: UIStatusBarAnimation {
        return .slide
    }
    

    Horizonal

    Vertical

    请注意横向视图的顶部和底部(在横向视图中更容易看到)。在顶部,播放器框架立即设置为旧位置,这会将所有内容向下移动20px(或状态栏的任何高度)

    它与隐藏的状态栏有关。有人有办法吗?

    1 回复  |  直到 8 年前
        1
  •  0
  •   Minebomber    8 年前

    我想出来了。这是一种黑客行为,没有经过充分测试,但这是我提出的解决方案。

    首先,获取一个变量以保存状态栏高度(不是0)。

    var statusBarHeight: CGFloat = UIApplication.shared.statusBarFrame.height != 0 ? UIApplication.shared.statusBarFrame.height : 20.0
    

    然后,设置状态栏框架更改的通知。

    NotificationCenter.default.addObserver(self, selector: #selector(SKPlayerViewController.updateLocalStatusBarFrameHeight), name: .UIApplicationDidChangeStatusBarFrame, object: nil)
    

    现在,在该方法中,仅当高度不是0时才更新变量。我们保存了高度,因为状态栏可能不是20(如果在通话中等)。

    @objc private func updateLocalStatusBarFrameHeight() {
            let height = UIApplication.shared.statusBarFrame.height
            if height > 0 {
                self.statusBarHeight = height
            }
        }
    

    exitFullScreenToEmbed() 将计算的帧原点减去 statusBarHeight 仅当不是横向时(因为状态栏隐藏在横向中)。

    private func exitFullScreenToEmbed() {
    
        var frame = self.view.window?.convert(self.view.frame, to: self.proxyView?.superview)
        self.proxyView?.superview?.addSubview(self.view)
    
        if !(UIApplication.shared.statusBarOrientation == .landscapeRight || UIApplication.shared.statusBarOrientation == .landscapeLeft) {
            frame?.origin.y -= self.statusBarHeight
        }
    
        self.view.frame = frame!
    
        self.isFullscreen = false
    
        UIView.animate(withDuration: 0.25, animations: {
    
            self.view.frame = self.proxyView!.frame
    
            self.view.layoutIfNeeded()
            self.setNeedsStatusBarAppearanceUpdate()
        }) { (_) in
            self.proxyView?.removeFromSuperview()
            self.proxyView = nil
        }
    }