QLPreviewController remove or add UIBarButtonItems

后端 未结 5 792
滥情空心
滥情空心 2020-12-01 11:21

I have seen this kind of question a lot on the internet but it seems no one really knows the answer?

I am using QLPreviewController for displaying PDF documents. I f

5条回答
  •  渐次进展
    2020-12-01 11:36

    By mixing a bit out of the existing answers/comments I was able to get this working for my use case: I needed to display files inside a UINavigationController and keep the ability of hiding/showing the UINavigationBar when the file content is tapped

    Based on the answer from Lukas Gross and the comment from nacross here's what I ended up doing:

    1. Add a (subclass of) QLPreviewController as a child view controller. This will show two navigation bars: one for the main navigation controller and one from the QLPreviewController
    2. Set up a top constraint from the container view to the top layout guide (named containerTop in the code)
    3. Set this constraint to a negative value, equal to the UINavigationBar plus the status bar, so that the QLPreviewController's UINavigationBar remains hidden under the main UINavigationBar.
    4. Using KVO, monitor the hidden property of the UINavigationBar so that we can (1) hide/show our main UINavigationBar and (2) reset the top constraint

    I ended up with something like this:

    var qlNavigationBar: UINavigationBar?
    
    
    func getQLNavigationBar(fromView view: UIView) -> UINavigationBar? {
        for v in view.subviews {
            if v is UINavigationBar {
                return v as? UINavigationBar
            } else {
                if let navigationBar = self.getQLNavigationBar(fromView: v) {
                    return navigationBar
                }
            }
        }
    
        return nil
    }
    
    func setObserverForNavigationBar() {
    
        self.qlNavigationBar = self.getQLNavigationBar(fromView: self.view)
    
        if let qln = self.qlNavigationBar {
            qln.addObserver(self, forKeyPath: "hidden", options: [NSKeyValueObservingOptions.New, NSKeyValueObservingOptions.Old], context: nil)
        }
    
    }
    
    override func observeValueForKeyPath(keyPath: String?, ofObject object: AnyObject?, change: [String : AnyObject]?, context: UnsafeMutablePointer) {
    
        self.navigationController?.setNavigationBarHidden(self.qlNavigationBar!.hidden, animated: true)
    
        self.containerTop.constant = self.qlNavigationBar!.hidden ? self.getStatusBarHeight() * -1 : self.getFullNavigationBarHeight() * -1
    
        UIView.animateWithDuration(0.5) {
            self.view.layoutIfNeeded()
        }
    
    }
    
    
    override func viewWillAppear(animated: Bool) {
        super.viewWillAppear(animated);
    
        self.setObserverForNavigationBar()
    
        self.containerTop.constant = self.getFullNavigationBarHeight() * -1
    
    }
    
    override func viewWillDisappear(animated: Bool) {
        super.viewWillDisappear(animated);
    
        if let qln = self.qlNavigationBar {
            qln.removeObserver(self, forKeyPath: "hidden")
        }
    
    }
    
    func getFullNavigationBarHeight() -> CGFloat {
        if let nav = self.navigationController {
            return nav.navigationBar.frame.origin.y + nav.navigationBar.frame.size.height
        }
        return 0
    }
    
    func getStatusBarHeight() -> CGFloat {
        return UIApplication.sharedApplication().statusBarFrame.size.height
    }
    

    The animations might need a little tweaking and it is hacky, but it's better than not having this possibility. It should be possible to adapt this strategy to other scenarios without the UINavigationController

    Note: If you have a crash when implementing the container view for the QLPreviewController from a storyboard, subclass the QLPreviewController and implement the initializer:

    class MyPreviewController: QLPreviewController {
    
        required init?(coder aDecoder: NSCoder) {
            super.init(nibName: nil, bundle: nil)
        }
    
    }
    

提交回复
热议问题