preferredStatusBarUpdateAnimation being ignored

2019-06-18 23:25发布

问题:

I have AuthViewController that is presenting MainViewController like so:

let mainVC = MainViewContoller()
mainVC.modalTransitionStyle = .CrossDissolve
authVC.presentViewController(mainVC, animated: true, completion: nil)

I want the AuthViewController to hide the status bar, but the MainViewController to show, like so:

AuthViewController {

    override func preferredStatusBarStyle() -> UIStatusBarStyle {
        return .LightContent
    }

    override func preferredStatusBarUpdateAnimation() -> UIStatusBarAnimation {
        return .Fade
    }

    override func prefersStatusBarHidden() -> Bool {
        return false
    }
}

MainViewController {

    override func preferredStatusBarStyle() -> UIStatusBarStyle {
        return .LightContent
    }

    override func preferredStatusBarUpdateAnimation() -> UIStatusBarAnimation {
        return .Fade
    }

    override func prefersStatusBarHidden() -> Bool {
        return false
    }
}

The status bar appears, however the preferredStatusBarUpdateAnimation() override is ignored. The status bar appears with no animation.

I have only been able to get it to animate by setting prefersStatusBarHidden on MainViewController to true until the viewDidAppear, then calling this:

UIView.animateWithDuration(0.3) {
    self.setNeedsStatusBarAppearanceUpdate()
}

I don't want to have to call this every time. What am I doing wrong?

回答1:

been searching for a solution to this too. However it seems you got half the solution already. You have to set up the overrides for the variables, but best practice for me was to create a private variable pair for each of the overrides, and have each override return it's respective private var (see bellow). You'd then change up the private variables and call setNeedsStatusBarAppearanceUpdate.

Plus, you need to set View controller-based status bar appearance in your info.plist to YES. Otherwise, it will still rely on the legacy UIApplication.shared... methods.

Here's a snippet:

override var preferredStatusBarUpdateAnimation: UIStatusBarAnimation {
    get {
        return .slide
    }
}

private var statusBarStyle : UIStatusBarStyle = .default

override var preferredStatusBarStyle: UIStatusBarStyle {
    get {
        return statusBarStyle
    }
}

private var statusBarStatus : Bool = false

override var prefersStatusBarHidden: Bool {
    get {
        return statusBarStatus
    }
}

which I then could call in a function like so: (this is one of my examples, so disregard the custom function).

func sliderView(sliderView: SliderView, didSlideToPlace: CGFloat, within: CGFloat) {

    let val = (within - (didSlideToPlace - sliderView.upCent))/(within)
    print(val)
    //Where you would change the private variable for the color, for example.
    if val > 0.5 {
        statusBarStyle = .lightContent
    } else {
        statusBarStyle = .default
    }
    UIView.animate(withDuration: 0.5, animations: {
        sliderView.top.backgroundColor = UIColor.black.withAlphaComponent(val)
        self.coverLayer.alpha = val
        self.scroll.backgroundColor = colors.lightBlueMainColor.withAlphaComponent(val)
    }, completion: {
        value in
        //If you do not call setNeedsStatusBarAppearanceUpdate() in an animation block, the animation variable won't be called it seems.
        UIView.animate(withDuration: 0.4, animations: {

            self.animating = true

            //Where you set the status for the bar (your part of the solution)
            self.statusBarStatus = false

            //Then you call for the refresh
            self.setNeedsStatusBarAppearanceUpdate()
        })
    })
}

You end up having to tune every view controller, but it seems like it's what you want to do, so hope it helps!