How to hide tab bar with animation in iOS?

后端 未结 15 1930
夕颜
夕颜 2020-11-30 19:20

So I have a button that is connected to a IBAction. When I press the button I want to hide the tab bar in my iOS app with a animation. This [self setTabBarHidden:hidde

15条回答
  •  南笙
    南笙 (楼主)
    2020-11-30 20:22

    My previous answer does not longer work on iOS14. I played with manipulating the frames of the different views, but it seams that the new implementation of the UITabBarController and UITabBar on iOS14 do some magic under the covers which makes this approach no longer working.

    I therefore switch to the approach that I hide the UITabBar by setting its alpha to zero and then I manipulate the bottom constraint (that you must pass in when calling the function) to bring the view's content down. This does however, mean that you must have such a constraint and the extension is more bound to your view then the previous approach.

    Make sure that the view you are displaying has clipToBounds = false otherwise you will just get a black area where the UITabBar once was!

    Here is the code of my UITabBarController.extensions.swift:

    import Foundation
    
    extension UITabBarController {
        
        private struct AssociatedKeys {
            // Declare a global var to produce a unique address as the assoc object handle
            static var orgConstraintConstant: UInt8 = 0
            static var orgTabBarAlpha       : UInt8 = 1
        }
        
        var orgConstraintConstant: CGFloat? {
            get { return objc_getAssociatedObject(self, &AssociatedKeys.orgConstraintConstant) as? CGFloat }
            set { objc_setAssociatedObject(self, &AssociatedKeys.orgConstraintConstant, newValue, .OBJC_ASSOCIATION_COPY) }
        }
        
        var orgTabBarAlpha: CGFloat? {
            get { return objc_getAssociatedObject(self, &AssociatedKeys.orgTabBarAlpha) as? CGFloat }
            set { objc_setAssociatedObject(self, &AssociatedKeys.orgTabBarAlpha, newValue, .OBJC_ASSOCIATION_COPY) }
        }
        
        func setTabBarVisible(visible:Bool, animated:Bool, bottomConstraint: NSLayoutConstraint) {
            // bail if the current state matches the desired state
            if (tabBarIsVisible() == visible) { return }
            //define segment animation duration (note we have two segments so total animation time = times 2x)
            let segmentAnimationDuration = animated ? 0.15 : 0.0
            //we should show it
            if visible {
                //animate moving up
                UIView.animate(withDuration:  segmentAnimationDuration,
                               delay: 0,
                               options: [],
                               animations: {
                                [weak self] in
                                guard let self = self else { return }
                                bottomConstraint.constant = self.orgConstraintConstant ?? 0
                                self.view.layoutIfNeeded()
                               },
                               completion: {
                                (_) in
                                //animate tabbar fade in
                                UIView.animate(withDuration: segmentAnimationDuration) {
                                    [weak self] in
                                    guard let self = self else { return }
                                    self.tabBar.alpha = self.orgTabBarAlpha ?? 0
                                    self.view.layoutIfNeeded()
                                }
                               })
                //reset our values
                self.orgConstraintConstant = nil
            }
            //we should hide it
            else {
                //save our previous values
                self.orgConstraintConstant = bottomConstraint.constant
                self.orgTabBarAlpha = tabBar.alpha
                //animate fade bar out
                UIView.animate(withDuration:  segmentAnimationDuration,
                               delay: 0,
                               options: [],
                               animations: {
                                [weak self] in
                                guard let self = self else { return }
                                self.tabBar.alpha = 0.0
                                self.view.layoutIfNeeded()
                               },
                               completion: {
                                (_) in
                                //then animate moving down
                                UIView.animate(withDuration: segmentAnimationDuration) {
                                    [weak self] in
                                    guard let self = self else { return }
                                    bottomConstraint.constant = bottomConstraint.constant - self.tabBar.frame.height + 4 // + 4 looks nicer on no-home button devices
                                    //self.tabBar.alpha = 0.0
                                    self.view.layoutIfNeeded()
                                }
                               })
            }
        }
        
        func tabBarIsVisible() ->Bool {
            return orgConstraintConstant == nil
        }
    }
    

    This is how it looks in my app (you can compare to my 1ste answer, the animation is a bit different but looks great) :

提交回复
热议问题