70

I use UITabBarController as a root view and app supports iOS 6 and above. Project class hierarchy is as below.

UITabBarController
  - tab1
    - UINavigationController
      - UIViewController
      - UIViewController
      .
      .
  - tab2
    - UINavigationController
      - UIViewController
      - UIViewController
      .
      .
      .
  - tab3
    - UIViewController
  - tab4
    - UIViewController

I used below code to change height of UITabBar in one of the UIViewControllers (which is inside UINavigationController) in above hierarchy.

CGRect tabbarFrame = self.tabBarController.tabBar.frame;
tabbarFrame.size.height += 60;
self.tabBarController.tabBar.frame = tabbarFrame;

But its not changing the height. UITabBar is displayed with default height. Though logging its value prints changed value as shown below.

<UITabBar: 0xb528f60; frame = (0 431; 320 109); autoresize = W+TM; layer = <CALayer: 0xb529080>>

How can I change UITabBar's height to achieve something like this:?

enter image description here

sasquatch
  • 6,126
  • 7
  • 39
  • 56
Geek
  • 7,950
  • 15
  • 68
  • 132
  • You can change default tabbar height but you need to subclass UITabBarController, i've done it before, i wrote it down on http://stackoverflow.com/questions/16740824/tab-bar-with-large-icons/16742065#16742065 – limon Apr 13 '14 at 15:43
  • Found this was working -> http://stackoverflow.com/a/27494228/1484378 – keji Dec 22 '14 at 17:32
  • I think you can also just set a height constraint, it seemed to work to me. – giovannipds Jul 05 '18 at 02:48

19 Answers19

141

I faced this issue and I was able to solve it.

You have to add following code to your subclass of UITabBarController class.

const CGFloat kBarHeight = 80;

- (void)viewWillLayoutSubviews {
    [super viewWillLayoutSubviews];

    CGRect tabFrame = self.tabBar.frame; //self.TabBar is IBOutlet of your TabBar
    tabFrame.size.height = kBarHeight;
    tabFrame.origin.y = self.view.frame.size.height - kBarHeight;
    self.tabBar.frame = tabFrame;
}

Swift:

override func viewWillLayoutSubviews() {
    super.viewWillLayoutSubviews()

    tabBar.frame.size.height = kBarHeight
    tabBar.frame.origin.y = view.frame.height - kBarHeight
}
kelin
  • 9,553
  • 6
  • 63
  • 92
Rushikesh
  • 1,535
  • 1
  • 9
  • 14
  • can you specify a bit more? i've added this code to my class that extends TabBarController and nothing happened – voghDev Dec 05 '14 at 16:26
  • I discarded changing tabBar height because it is a constant defined by Apple, but still couldn't do it (in case I'd be finally interested in resizing it). – voghDev Jan 19 '15 at 12:01
  • 8
    Your `viewWillLayoutSubviews` implementation should call super, probably as the first line. – Dklionsk Nov 19 '15 at 17:37
  • 1
    @Dklionsk It could call `super`, but it doesn't have to: `The default implementation of this method does nothing.` (from the docs) – dmirkitanov Feb 18 '16 at 22:39
  • 1
    @dmirkitanov that's true for a `UIViewController` but may not be true for `UITabBarController` – Alex Pretzlav Feb 23 '16 at 23:11
  • Swift 3.0 version. import Foundation import UIKit class NavigationTabBarController: UITabBarController{ let kBarHeight = CGFloat(80) override func viewWillLayoutSubviews() { var tabFrame = self.tabBar.frame //self.TabBar is IBOutlet of your TabBar tabFrame.size.height = kBarHeight tabFrame.origin.y = self.view.frame.size.height - kBarHeight self.tabBar.frame = tabFrame } } – SaundersB Jun 17 '17 at 17:02
  • doesn't work well with scrollviews which dont adjust accordingly – Peter Lapisu Oct 29 '18 at 10:37
  • @dmirkitanov, the default implementation of `UIViewController` does nothing, but it's a `UITabBarController` subclass! – kelin Sep 08 '19 at 07:26
  • 19
    Changing `viewWillLayoutSubviews` to `viewDidLayoutSubviews` works in iOS 13. – arlomedia Nov 05 '19 at 07:48
  • doesn't really work for iphonex because of the bottom line thing. – Omar Awamry Feb 23 '20 at 21:07
43

For iOS 8.2, Xcode 6.2 Swift language:

Create a "DNMainTabVC.swift" (DeveloperNameMainTabViewController.swift file) for your UITabBarController (of type UITabBarController) and connect it to your storyboard VC.

Add the following lines:

override func viewWillLayoutSubviews() {
    var tabFrame = self.tabBar.frame
    // - 40 is editable , the default value is 49 px, below lowers the tabbar and above increases the tab bar size
    tabFrame.size.height = 40
    tabFrame.origin.y = self.view.frame.size.height - 40
    self.tabBar.frame = tabFrame
}

This worked for me.

eric.mitchell
  • 8,501
  • 12
  • 50
  • 91
MB_iOSDeveloper
  • 4,076
  • 4
  • 21
  • 35
  • @MS_iOSDeveloper: What do you mean "connect it to storyboard VC"? How to connect it? Thanks! – Rock May 10 '15 at 06:37
  • 1
    You go to your storyboard. Click the viewcontroller, and go to the right side of Xcode to the "view inspector". Under the third tab (which looks like a newspaper) you will find a "Class" Label. The placeholder grey text should say "UIViewController". There you type the name of your viewcontroller file ,ex. "DNMainTabVC". After that a arrow will appear in the Box beside "DNMainTabVC". This means that the viewcontroller file (.swift) is connected to the storyboard element. What ever you write in "DNMainTabVC.swift" will have effect on the storyboard VC. – MB_iOSDeveloper May 11 '15 at 07:58
  • @MS_iOSDeveloper got it. so it's selecting custom class. I thought you meant some "dragging" action to "connect". I got it work. thanks for explaining! – Rock May 12 '15 at 23:07
39

Swift3.0, Swift 4.0 compatible

Pre-iPhone X default tab bar height: 49pt

iPhone X default tab bar height: 83pt

A universal solution supporting every iOS device including iPhone X screen size would look like this:

  1. Capture UITabBar's default height:

    fileprivate lazy var defaultTabBarHeight = { tabBar.frame.size.height }()
    
  2. Adjust UITabBar's height:

        override func viewWillLayoutSubviews() {
            super.viewWillLayoutSubviews()
    
            let newTabBarHeight = defaultTabBarHeight + 16.0
    
            var newFrame = tabBar.frame
            newFrame.size.height = newTabBarHeight
            newFrame.origin.y = view.frame.size.height - newTabBarHeight
    
            tabBar.frame = newFrame
        }
    
Kiarash Asar
  • 391
  • 3
  • 4
  • 1
    This will make the tabBar jump when animating a view change (like a status bar hiding) – jakedunc Sep 04 '18 at 01:50
  • 2
    @jakedunc I think it's the issue that S. Azzopardi said, I put this code in viewDidLayoutSubviews() and it works fine. – ioio007 Nov 14 '18 at 09:19
  • @ioio007 Hi this works fine for iPhone x and other devices. But when i increase the height UIView bottom is hiding according the increase value. Help me to get the solution. – Saravanan Jun 28 '19 at 06:02
  • Hi @Saravanan, looks like your problem is the same with the comment below this answer: https://stackoverflow.com/a/44293634/7144402 – ioio007 Jul 01 '19 at 08:33
  • Change viewWillLayoutSubviews to viewDidLayoutSubviews in UITabBarViewController Class It will work fine. it is worked for me. – Sahil Omer Dec 18 '20 at 07:12
39

Tested in XCode 9.0 and Swift 4

As suggested in previous answers - inherit UITabBar and override sizeThatFits, but mark height as @IBInspectable, so it could be set in the Interface Builder:

import UIKit

class CustomTabBar : UITabBar {
    @IBInspectable var height: CGFloat = 0.0

    override func sizeThatFits(_ size: CGSize) -> CGSize {
        var sizeThatFits = super.sizeThatFits(size)
        if height > 0.0 {
            sizeThatFits.height = height
        }
        return sizeThatFits
    }
}

Set CustomTabBar class for the UITabBar in the Identity Inspector (⌥⌘3):

Tab Bar Identity Inspector

Then set desired Height (greater than 0.0) in the Attributes Inspector (⌥⌘4):

Tab Bar Attributes Inspector

msrdjan
  • 775
  • 8
  • 8
  • Have you thought about making an **extension** instead of Custom Class. And then specifying `@IBInspectable var height` in the extension. If that is possible, the second step of specifying the Custom Class can be avoided. – Vipin Johney Dec 08 '17 at 07:39
  • 2
    Doesn't works well on iPhone X. You have to use this solution: https://stackoverflow.com/a/50346008/1702909 – Jindřich Rohlík Sep 25 '18 at 13:25
29

Create a custom subclass of type UITabBar, then implement the following method :

@implementation CustomTabBar
#define kTabBarHeight = // Input the height we want to set for Tabbar here
-(CGSize)sizeThatFits:(CGSize)size
{
    CGSize sizeThatFits = [super sizeThatFits:size];
    sizeThatFits.height = kTabBarHeight;

    return sizeThatFits;
}
@end

Hope this will work.

sKhan
  • 7,934
  • 16
  • 51
  • 51
  • 1
    Great! This so far is the best solution I've seen. As it doesn't modify directly the frame but instead changes the expected size! Great! – vilanovi May 21 '15 at 14:52
  • This answer does not have side effects in terms of auto layout of the inner view controllers, and it should be the accepted answer. – tsuz Apr 26 '18 at 02:58
  • How can we use this when we make tab bar controller programmatically? – EI Captain v2.0 Sep 04 '19 at 06:37
14

For Swift 4

extension UITabBar {

     override open func sizeThatFits(_ size: CGSize) -> CGSize {
     var sizeThatFits = super.sizeThatFits(size)
     sizeThatFits.height = 60 // adjust your size here
     return sizeThatFits
    }
 }
Merichle
  • 586
  • 8
  • 12
11

Swift 2.0:

var tabBar:UITabBar?

override func viewWillLayoutSubviews() {
    var tabFrame: CGRect = self.tabBar!.frame
    tabFrame.size.height = 60
    tabFrame.origin.y = self.view.frame.size.height - 60
    self.tabBar!.frame = tabFrame
}
A.G
  • 13,048
  • 84
  • 61
  • Not working anymore in Swift 2.2. It leaves a clear space below the original tab bar frame – jaytrixz Apr 28 '16 at 10:04
  • @jaytrixz Had the same issue. The blank space will appear if you put Alvin's code in viewDidLoad(), but not if you put it in viewWillLayoutSubviews() as suggested – Kqtr May 31 '17 at 19:51
11

Swift 3.0+ Replace 200 to your desired height in below code.

   extension UITabBar {
        override open func sizeThatFits(_ size: CGSize) -> CGSize {
            return CGSize(width: UIScreen.main.bounds.width, height: 200)
        }
    }
William Hu
  • 12,918
  • 8
  • 85
  • 98
  • Be careful! The behavior is undefined as to which method implementation is used at runtime - original from UITabbar class or your extension – Alexander Larionov Aug 25 '17 at 15:20
  • Works like charm – rockdaswift Sep 22 '17 at 14:14
  • You should **NOT** be overriding methods using Swift extensions (or Objective-C categories, for that matter). If you want to use the `sizeThatFits()` approach, use this solution instead: https://stackoverflow.com/a/46425620/538491 – Roberto Nov 21 '17 at 12:02
10

Swift 4 & compatible with iphone x

class CustomTabBar : UITabBar {

@IBInspectable var height: CGFloat = 65.0

override open func sizeThatFits(_ size: CGSize) -> CGSize {
    guard let window = UIApplication.shared.keyWindow else {
        return super.sizeThatFits(size)
    }
    var sizeThatFits = super.sizeThatFits(size)
    if height > 0.0 {

        if #available(iOS 11.0, *) {
            sizeThatFits.height = height + window.safeAreaInsets.bottom
        } else {
            sizeThatFits.height = height
        }
    }
    return sizeThatFits
}
}
seggy
  • 1,046
  • 2
  • 15
  • 36
  • I used this method definition inside an `extension`, because I'm creating all the UI elements programmatically and, when I tried to set the `tabBar` of my `tabBarController` by overriding the `tabBar` attribute, it displays an empty tabBar (without items) – mauricioconde Mar 17 '20 at 19:36
  • guard let window = UIApplication.shared.keyWindow is deprecated in iOS 13.0. So please update. – Chandan Jee Sep 18 '20 at 14:57
7

Building up on previous answers and updating for Swift 3.

Subclass UITabController and make sure to assign your new custom class to the Identity Inspector of your UITabController.

Swift 3.0

class MainTabBarController: UITabBarController {

    override func viewWillLayoutSubviews() {
        var newTabBarFrame = tabBar.frame

        let newTabBarHeight: CGFloat = 60
        newTabBarFrame.size.height = newTabBarHeight
        newTabBarFrame.origin.y = self.view.frame.size.height - newTabBarHeight

        tabBar.frame = newTabBarFrame
    }
}

Warning: if you get a blank space below your tab bar, make sure you did put this code in viewWillLayoutSubviews() and not viewDidLoad().

Kqtr
  • 5,397
  • 3
  • 17
  • 27
  • This works, however some of the view got blocked by tab bar because of the increased height.. Any idea how to solve this? – John Nov 02 '18 at 10:18
  • Hey @john. Are you pinning them to the safe area bottom margin? – Kqtr Nov 04 '18 at 11:02
  • Hi @Kqtr, I pinned the view to the bottom view like: `NSLayoutConstraint(item: tableView, attribute: NSLayoutAttribute.bottom, relatedBy: NSLayoutAttribute.equal, toItem: view, attribute: NSLayoutAttribute.bottom, multiplier: 1, constant: 0)` I found `safeAreaInsets` and `safeAreaLayoutGuide` but the feature only available for iOS 11 and above. Is this what you're referring to? – John Nov 05 '18 at 05:58
  • Yes, you could try, on iOS 11 and above, to use view.safeAreaLayoutGuide.bottomAnchor, where view is the VC's main view. And below iOS 11, pin to VC's bottomLayoutGuide.topAnchor. Currently, you are using the view's bottom, and the view might go lower than those bottom guides. – Kqtr Nov 05 '18 at 22:00
  • @john also, FYI, for convenience I created 4 variables in an VC extension that provides simple constraints to use (repeat for left right & top): extension UIViewController { var safeBottomAnchor: NSLayoutYAxisAnchor { if #available(iOS 11.0, *) { return view.safeAreaLayoutGuide.bottomAnchor } else { return bottomLayoutGuide.topAnchor } } } – Kqtr Nov 05 '18 at 22:01
  • good one, I have done that but did it as a `UIView` extension, like: `extension UIView { var safeTopAnchor: NSLayoutYAxisAnchor { if #available(iOS 11.0, *) { return self.safeAreaLayoutGuide.topAnchor } else { return self.topAnchor } }` Thank for sharing BTW – John Nov 06 '18 at 08:00
  • My pleasure! And careful because below iOS 11, I suspect that your extension will pin to the top of the view which, in the case of a VC's main view, will be the top of the status bar, whereas it will be the bottom of the status bar using the VC's topLayoutGuide. – Kqtr Nov 06 '18 at 11:43
7

For some reason, the answer from @Rushikesh was working pretty well until iOS 10 but I had some issues with iOS 11 and Swift 3.2.

The tabBar was changing its frame every time I touched a new tab.

I fixed this by putting the code in the viewDidLayoutSubviews() function instead of viewWillLayoutSubviews()

Swift 3 :

override func viewDidLayoutSubviews() {

    super.viewDidLayoutSubviews()
    var tabFrame            = tabBar.frame
    tabFrame.size.height    = 65
    tabFrame.origin.y       = view.frame.size.height - 65
    tabBar.frame            = tabFrame
}
Jean-François Corbett
  • 34,562
  • 26
  • 126
  • 176
S. Azzopardi
  • 71
  • 1
  • 3
5

Xamarin implementation:

public override void ViewWillLayoutSubviews()
{
    base.ViewWillLayoutSubviews();
    const float newTabBarHeight = 40f;
    TabBar.Frame = new CGRect(TabBar.Frame.X, TabBar.Frame.Y + (TabBar.Frame.Height - newTabBarHeight), TabBar.Frame.Width, newTabBarHeight);
}
Alexey Strakh
  • 10,508
  • 17
  • 76
  • 146
5

Edited Kiarash Asar's answers with use of Safe Area:

override func viewWillLayoutSubviews() {
    super.viewWillLayoutSubviews()

    var safeAreaBottomInset: CGFloat = 0.0

    if #available(iOS 11.0, *) {
        safeAreaBottomInset = view.safeAreaInsets.bottom
    }

    let newTabBarHeight: CGFloat = {{myDesiredHeight}} + safeAreaBottomInset

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

    tabBar.frame = newFrame
}
jonaszmclaren
  • 2,399
  • 17
  • 29
4

You can modify the tab bar's height by subclassing it. I actually did this long time ago. xcode 6.0

override func sizeThatFits(_ size: CGSize) -> CGSize {
    return CGSize(width: super.sizeThatFits(size).width, height: 60)
}

That should return its default width with the height of 60pts.

appsunited
  • 1,567
  • 14
  • 21
NFerocious
  • 3,034
  • 2
  • 15
  • 36
4

this is also one way to do that

extension UITabBar {

override public func sizeThatFits(size: CGSize) -> CGSize {
    super.sizeThatFits(size)
    var sizeThatFits = super.sizeThatFits(size)
    sizeThatFits.height = 71 // or whatever height you need
    return sizeThatFits
   } 
}
Sultan Ali
  • 1,853
  • 23
  • 21
3

WORKS WITH ALL SCREEN SIZES: Set the tabBarHeight to the (original height of the tabBar - 20) this is important so you can use it later in the viewDidLayoutSubviews, also better than hard coding the size you want. Since that size might not work on all screens.

Window safe area insets keeps the necessary padding at the bottom of the tab bar height in order to maintain the distance from the bottom edge of the screen.

var tabBarHeight = CGFloat()

override func viewDidLoad() {
        super.viewDidLoad()
        tabBarHeight = self.tabBar.frame.height - 20
    }

    override func viewDidLayoutSubviews() {
        super.viewDidLayoutSubviews()
        var tabFrame = self.tabBar.frame
        guard let window = UIApplication.shared.keyWindow else {return}
        tabFrame.size.height = tabBarHeight + window.safeAreaInsets.bottom
        self.tabBar.frame = tabFrame
    }
1

iPhoneX have have different height so if we move to smaller height then tabbar shape will be bad in iPhoneX

- (void)viewWillLayoutSubviews
{
    int requiredHeight = 55;
    CGRect tabFrame = self.tabBar.frame;
    if (tabFrame.size.height < requiredHeight)
    {
        tabFrame.size.height = requiredHeight;
        tabFrame.origin.y = self.view.frame.size.height - requiredHeight;
        self.tabBar.frame = tabFrame;
    }
}
sasquatch
  • 6,126
  • 7
  • 39
  • 56
Abeer Iqbal
  • 779
  • 5
  • 8
1

Swift 5.3.1, XCode 11+, iOS 14:

import UIKit

class CustomTabBar: UITabBar {
    let height: CGFloat = 62
    
    override open func sizeThatFits(_ size: CGSize) -> CGSize {
        guard let window = UIApplication.shared.connectedScenes
                .filter({$0.activationState == .foregroundActive})
                .map({$0 as? UIWindowScene})
                .compactMap({$0})
                .first?.windows
                .filter({$0.isKeyWindow}).first else {
            return super.sizeThatFits(size)
        }

        var sizeThatFits = super.sizeThatFits(size)
        if #available(iOS 11.0, *) {
            sizeThatFits.height = height + window.safeAreaInsets.bottom
        } else {
            sizeThatFits.height = height
        }
        return sizeThatFits
    }
}
David Kyslenko
  • 423
  • 5
  • 18
1

class TabBarVC: UITabBarController {

//MARK:- Variable
let HEIGHT_TAB_BAR:CGFloat = 500

override func viewDidLoad() {
    super.viewDidLoad()
    
    // Do any additional setup after loading the view.
}


override func viewDidLayoutSubviews() {
    super.viewDidLayoutSubviews()
    var tabFrame = self.tabBar.frame
    tabFrame.size.height = HEIGHT_TAB_BAR
    tabFrame.origin.y = self.view.frame.size.height - HEIGHT_TAB_BAR
    self.tabBar.frame = tabFrame
}

}

Worked fine for me.

Sahil Omer
  • 73
  • 9