CyberMew
CyberMew

Reputation: 1421

Change position of UITabBarButton in tab bar

I increased my tab bar height via changing the frame of the tabBar in my custom UITabBarController class in viewDidLayoutSubviews().

However, the tab bar buttons do not remain vertically centered.

I tried to access the UITabBarButton views and set the frame manually, but it does not stay (has no effect). Not sure why the new frame is being reset/ignored. I also tried doing it in viewDidAppear() to no avail. Running out of ideas. Using Reveal app to edit it has no issues (not sure what they are doing to get it to stick).

Is there any way I can edit the frame of the button?

Upvotes: 0

Views: 2568

Answers (1)

CyberMew
CyberMew

Reputation: 1421

I figured it out. It was a silly mistake of mine - forgot to remove a test set frame code. Either way, here is what I did and it has to be done in viewDidAppear() because that is where the button frames are properly updated and only then can we act on it (if anyone knows of a better way, please leave a comment!).

First of all I had to increase the height of the tab bar:

    override func viewDidLayoutSubviews() {
        super.viewDidLayoutSubviews()
        // Increase by 16 pt.
        let newTabBarHeight = tabBar.frame.size.height + 16

        var newFrame = tabBar.frame
        newFrame.size.height = newTabBarHeight
        newFrame.origin.y = view.frame.size.height - newTabBarHeight

        tabBar.frame = newFrame
    }

Then shift the buttons y-position:

    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)

        let buttons = tabBar.subviews.filter { String(describing: type(of: $0)) == "UITabBarButton" }
        buttons.forEach {
            // Getting the button's superview height (probably can just take the tab bar `tabBar.frame.size.height` and remove the `if`).
            if let superviewHeight = $0.superview?.frame.height {
                // Accounted for the safe area insets for iPhone X and above.
                $0.center = CGPoint(x: $0.frame.midX, y: superviewHeight * 0.5 - ((appDelegate.window?.safeAreaInsets.bottom ?? 0) * 0.5))
            }
        }
    }

The above should hopefully work if the device rotated or for an iPad, but I did not test it out.

Here is alternate version using autolayout constraints for reference (since this is not so flexible if the bar changes width):

    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)

        let buttons = tabBar.subviews.filter { String(describing: type(of: $0)) == "UITabBarButton" }
        buttons.forEach {
            $0.translatesAutoresizingMaskIntoConstraints = false
            NSLayoutConstraint.activate([
                $0.centerYAnchor.constraint(equalTo: superview.centerYAnchor,
                                            constant: ((appDelegate.window?.safeAreaInsets.bottom ?? 0) * 0.5) : 0),
                $0.heightAnchor.constraint(equalToConstant: $0.frame.height),
                $0.widthAnchor.constraint(equalToConstant: $0.frame.width),
                $0.leadingAnchor.constraint(equalTo: superview.leadingAnchor, constant: $0.frame.minX)
            ])

    }

Unfortunately both will visibly show a jump in the buttons (moving from top to center) since it happens in viewDidAppear(), even for the autolayout constraints version. The alternative solution I believe would be to create our own tab bar though I have not done that before and am not sure what other implications that would have.

Hope this helps someone out as well.

Upvotes: 1

Related Questions