Reputation: 8320
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:?
Upvotes: 76
Views: 116552
Reputation: 206
I've used a solution with CustomTabBar
, but I ended up getting a lot of exceptions which didn't tell me anything. Every time I was getting a different error, or sometimes no error at all. For example one of the errors in a random place:
Thread 1: EXC_BAD_ACCESS (code=1, address=0x18)
Or:
malloc: Incorrect checksum for freed object 0x14ce4c790: probably modified after being freed.
Corrupt value: 0xb000000000000001
malloc: *** set a breakpoint in malloc_error_break to debug
I searched for a solution and on Apple's dev-forum user eskimo advised to use Standard Memory Debugging Tools.
Zombies instrument didn't help, but Address Sanitizer helped to identify the problem at once!
Error log:
SUMMARY: AddressSanitizer: heap-buffer-overflow MyTabBarController.swift in MyTabBarController.CustomTabBar.hasBanner.setter
thread #1: tid = 0x6801d, 0x00000001089bb250 libclang_rt.asan_iossim_dynamic.dylib`__asan::AsanDie(), queue = 'com.apple.main-thread', stop reason = Heap buffer overflow
{
"access_size": 1,
"access_type": 1,
"address": 4918104816,
"description": "heap-buffer-overflow",
"instrumentation_class": "AddressSanitizer",
"pc": 4382625148,
"stop_type":
The problem was that I used an instance variable in CustomTabBar. For some reason it was causing crashes. I've switched the var to a static and it solved the problem!
Here is the working code:
class MyTabBarController: UITabBarController {
override func viewDidLoad() {
// We have to put all init logic here because:
// `UITabBarController` calls `loadView()` inside `super.init()` method,
// which causes the call to `viewDidLoad()`.
// So the `viewDidLoad()` method will be called before `init()` has finished its job.
object_setClass(tabBar, CustomTabBar.self)
CustomTabBar.hasBanner = InAppPurchaseManager.shared.activeSubscription == nil
super.viewDidLoad()
// ...
}
// ...
}
extension MyTabBarController {
class CustomTabBar: UITabBar {
// We have to use a static var `hasBanner`
// because an instance var causes a Heap Buffer Overflow.
static var hasBanner: Bool = true // <------------------- THE SOLUTION
override func sizeThatFits(_ size: CGSize) -> CGSize {
var sizeThatFits = super.sizeThatFits(size)
sizeThatFits.height = Constants.Layout.tabBarHeight + (Self.hasBanner ? 44 : 0)
return sizeThatFits
}
}
}
Upvotes: 0
Reputation: 719
For SwiftUI, I use Introspect Introspect
Then in your TabView view modifier, increase the size of your view by adding to the height. Here I am adding 7 pts then another 2.5 pts for a custom divider line. And I added it differently for iPhone vs. iPad.
.introspectTabBarController { UITabBarController in
if sizeClass == .compact {
let barIncrease = UIView(frame: CGRect(x: 0, y: -7, width: UITabBarController.tabBar.frame.size.width, height: 9))
barIncrease.backgroundColor = UIColor(hex: "#508FD6FF")
UITabBarController.tabBar.addSubview(barIncrease)
let lineView = UIView(frame: CGRect(x: 0, y: -9.5, width: UITabBarController.tabBar.frame.size.width, height: 2.5))
lineView.backgroundColor = UIColor(hex: "#508FD6FF")
UITabBarController.tabBar.addSubview(lineView)
} else {
let lineView = UIView(frame: CGRect(x: 0, y: -2.5, width: UITabBarController.tabBar.frame.size.width, height: 2.5))
lineView.backgroundColor = UIColor(hex: "#508FD6FF")
UITabBarController.tabBar.addSubview(lineView)
}
}
Upvotes: 0
Reputation: 1196
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.connectedScenes
.compactMap({$0 as? UIWindowScene})
.first?.windows
.filter({$0.isKeyWindow}).first 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
}
}
Upvotes: 11
Reputation: 7178
For a UITabBarController subclass
Create a subclass from UITabBar
class CustomTabBar : UITabBar {
override open func sizeThatFits(_ size: CGSize) -> CGSize {
super.sizeThatFits(size)
var sizeThatFits = super.sizeThatFits(size)
sizeThatFits.height = 200
return sizeThatFits
}
}
and set the class in the constructor
init() {
super.init(nibName: nil, bundle: nil)
object_setClass(self.tabBar, CustomTabBar.self)
}
Upvotes: 2
Reputation: 29
It helped me
override func viewDidLayoutSubviews() {
super.viewWillLayoutSubviews()
tabBar.frame.size.height = 60
tabBar.frame.origin.y = view.frame.height - 60
}
Upvotes: 1
Reputation: 710
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
}
}
Upvotes: 15
Reputation: 120082
Just add more inset to the bottom of the safe area:
additionalSafeAreaInsets.bottom = 40
Upvotes: 6
Reputation: 179
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.
Upvotes: 2
Reputation: 889
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
}
}
Upvotes: 4
Reputation: 2589
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
}
}
Upvotes: 4
Reputation: 1571
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
}
Upvotes: 143
Reputation: 49
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
}
Upvotes: 3
Reputation: 2489
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
}
Upvotes: 5
Reputation: 1346
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;
}
}
Upvotes: 1
Reputation: 3280
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.
Upvotes: 4
Reputation: 835
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):
Then set desired Height
(greater than 0.0
) in the Attributes Inspector (⌥⌘4):
Upvotes: 45
Reputation: 71
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
}
Upvotes: 7
Reputation: 429
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:
Capture UITabBar's default height:
fileprivate lazy var defaultTabBarHeight = { tabBar.frame.size.height }()
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
}
Upvotes: 42
Reputation: 16189
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)
}
}
Upvotes: 11
Reputation: 11722
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);
}
Upvotes: 5
Reputation: 5935
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().
Upvotes: 7
Reputation: 4208
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.
Upvotes: 41
Reputation: 14294
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
}
Upvotes: 11
Reputation: 10374
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.
Upvotes: 30