ChatGPT解决这个技术问题 Extra ChatGPT

Remove tab bar item text, show only image

Simple question, how can I remove the tab bar item text and show only the image?

I want the bar items to like in the instagram app:

https://i.stack.imgur.com/WUeBF.png

In the inspector in xcode 6 I remove the title and choose a @2x (50px) and a @3x (75px) image. However the image does not use the free space of the removed text. Any ideas how to achieve the same tab bar item image like in the instagram app?

using "" for the title, maybe?
Setting offsets is just a trick, correct answer is a little bit below. You should use navigationItem.title = "some title"

m
mustafa

You should play with imageInsets property of UITabBarItem. Here is sample code:

let tabBarItem = UITabBarItem(title: nil, image: UIImage(named: "more")
tabBarItem.imageInsets = UIEdgeInsets(top: 9, left: 0, bottom: -9, right: 0)

Values inside UIEdgeInsets depend on your image size. Here is the result of that code in my app:

https://i.stack.imgur.com/cEJZV.png


You can also adjust the image insets in the inspector.
Magic numbers are a bad idea. Please see my answer for a universally compatible way to accomplish the same thing.
This no longer works in iOS 11 - if you double click the active tab it'll double the insets for some reason.
@BenGotow same problem you got any solution ?
@DixitAkabari other people have already posted some good solutions for iOS 11
d
ddiego
// Remove the titles and adjust the inset to account for missing title
for(UITabBarItem * tabBarItem in self.tabBar.items){
    tabBarItem.title = @"";
    tabBarItem.imageInsets = UIEdgeInsetsMake(6, 0, -6, 0);
}

Instead of removing the title change the text color to clear. Title can be useful.
Kodos to Eduardo! Made me realize a good option is also to set a vertical UIOffset on the item's titlePositionAjustement
Where do you put this in your custom TabBar Controller?
n
nuynait

Here is how you do it in a storyboard.

Clear the title text, and set the image inset like the screenshot below

https://i.stack.imgur.com/Xv9FW.png

Remember the icon size should follow the apple design guideline

https://i.stack.imgur.com/RbACa.png

This means you should have 25px x 25px for @1x, 50px x 50px for @2x, 75px x 75px for @3x


n
nsinvocation

Using approach with setting each UITabBarItems title property to "" and update imageInsets won't work properly if in view controller self.title is set. For example if self.viewControllers of UITabBarController are embedded in UINavigationController and you need title to be displayed on navigation bar. In this case set UINavigationItems title directly using self.navigationItem.title, not self.title.


This seems like a way cleaner method. +1 @Oleg this should be marked as the answer.
M
Marcos Reboucas

If you're using storyboards this would be you best option. It loops through all of the tab bar items and for each one it sets the title to nothing and makes the image full screen. (You must have added an image in the storyboard)

for tabBarItem in tabBar.items!
{
   tabBarItem.title = ""
   tabBarItem.imageInsets = UIEdgeInsetsMake(6, 0, -6, 0)
}

Good to note that if you don't set both top and bottom insets the image will end up being warped.
C
Community

Swift version of ddiego answer

Compatible with iOS 11

Call this function in viewDidLoad of every first child of the viewControllers after setting title of the viewController

Best Practice:

Alternativelly as @daspianist suggested in comments

Make a subclass of like this class BaseTabBarController: UITabBarController, UITabBarControllerDelegate and put this function in the subclass's viewDidLoad

func removeTabbarItemsText() {

    var offset: CGFloat = 6.0

    if #available(iOS 11.0, *), traitCollection.horizontalSizeClass == .regular {
        offset = 0.0
    }

    if let items = tabBar.items {
        for item in items {
            item.title = ""
            item.imageInsets = UIEdgeInsets(top: offset, left: 0, bottom: -offset, right: 0)
        }
    }
}

Great function! You could alternatively make a subclass of like this class BaseTabBarController: UITabBarController, UITabBarControllerDelegate and put this function in the subclass's viewDidLoad
G
GDanger

iOS 11 throws a kink in many of these solutions, so I just fixed my issues on iOS 11 by subclassing UITabBar and overriding layoutSubviews.

class MainTabBar: UITabBar {

    override func layoutSubviews() {
        super.layoutSubviews()

        // iOS 11: puts the titles to the right of image for horizontal size class regular. Only want offset when compact.
        // iOS 9 & 10: always puts titles under the image. Always want offset.
        var verticalOffset: CGFloat = 6.0

        if #available(iOS 11.0, *), traitCollection.horizontalSizeClass == .regular {
            verticalOffset = 0.0
        }

        let imageInset = UIEdgeInsets(
            top: verticalOffset,
            left: 0.0,
            bottom: -verticalOffset,
            right: 0.0
        )

        for tabBarItem in items ?? [] {
            tabBarItem.title = ""
            tabBarItem.imageInsets = imageInset
        }
    }
}

this is the only thing that worked for me but I had to put the code inside 'override func viewDidLayoutSubviews' of MyTabBarController's subclass. I subclassed the tabBarController and named it that
Solution worked for me, nicely. I used it as extension so it's simpler to add
@LanceSamaria this worked without me needing to touch the tab bar controller code
c
chrs

I used the following code in my BaseTabBarController's viewDidLoad. Note that in my example, I have 5 tabs, and selected image will always be base_image + "_selected".

// Get tab bar and set base styles
let tabBar = self.tabBar;
tabBar.backgroundColor = UIColor.whiteColor()

// Without this, images can extend off top of tab bar
tabBar.clipsToBounds = true

// For each tab item..
let tabBarItems = tabBar.items?.count ?? 0
for i in 0 ..< tabBarItems {
    let tabBarItem = tabBar.items?[i] as UITabBarItem

    // Adjust tab images (Like mstysf says, these values will vary)
    tabBarItem.imageInsets = UIEdgeInsetsMake(5, 0, -6, 0);

    // Let's find and set the icon's default and selected states
    // (use your own image names here)
    var imageName = ""
    switch (i) {
    case 0: imageName = "tab_item_feature_1"
    case 1: imageName = "tab_item_feature_2"
    case 2: imageName = "tab_item_feature_3"
    case 3: imageName = "tab_item_feature_4"
    case 4: imageName = "tab_item_feature_5"
    default: break
    }
    tabBarItem.image = UIImage(named:imageName)!.imageWithRenderingMode(.AlwaysOriginal)
    tabBarItem.selectedImage = UIImage(named:imageName + "_selected")!.imageWithRenderingMode(.AlwaysOriginal)
}

Instead of using for var i = 0; i < tabBar... , you could have just said; for tabBarItems in tabBar.items!
t
tapizquent

Swift 4 approach

I was able to do the trick by implementing a function that takes a TabBarItem and does some formatting to it.

Moves the image a little down to make it be more centered and also hides the text of the Tab Bar. Worked better than just setting its title to an empty string, because when you have a NavigationBar as well, the TabBar regains the title of the viewController when selected

func formatTabBarItem(tabBarItem: UITabBarItem){
    tabBarItem.imageInsets = UIEdgeInsets(top: 6, left: 0, bottom: -6, right: 0)
    tabBarItem.setTitleTextAttributes([NSAttributedStringKey.foregroundColor:UIColor.clear], for: .selected)
    tabBarItem.setTitleTextAttributes([NSAttributedStringKey.foregroundColor:UIColor.clear], for: .normal)
}

Latest syntax

extension UITabBarItem {
    func setImageOnly(){
        imageInsets = UIEdgeInsets(top: 6, left: 0, bottom: -6, right: 0)
        setTitleTextAttributes([NSAttributedString.Key.foregroundColor:UIColor.clear], for: .selected)
        setTitleTextAttributes([NSAttributedString.Key.foregroundColor:UIColor.clear], for: .normal)
    }
 }

And just use it in your tabBar as:

tabBarItem.setImageOnly()

E
Ezekiel Victor

Here is a better, more foolproof way to do this other than the top answer:

[[UITabBarItem appearance] setTitleTextAttributes:@{NSForegroundColorAttributeName: [UIColor clearColor]}
                                         forState:UIControlStateNormal];
[[UITabBarItem appearance] setTitleTextAttributes:@{NSForegroundColorAttributeName: [UIColor clearColor]}
                                         forState:UIControlStateHighlighted];

Put this in your AppDelegate.didFinishLaunchingWithOptions so that it affects all tab bar buttons throughout the life of your app.


This is only hides the title and doesn't adjust the position of image.
Yeah but the question said nothing about adjusting the image. Just hiding the text. And well hiding the text at the detriment of removing the title from a view controller seems wrong. Especially when you could be using that title to show it as part of your navigationviewcontroller
F
Federico Zanetello

A minimal, safe UITabBarController extension in Swift (based on @korgx9 answer):

extension UITabBarController {
  func removeTabbarItemsText() {
    tabBar.items?.forEach {
      $0.title = ""
      $0.imageInsets = UIEdgeInsets(top: 6, left: 0, bottom: -6, right: 0)
    }
  }
}

a
aehlke

Based on the answer of ddiego, in Swift 4.2:

extension UITabBarController {
    func cleanTitles() {
        guard let items = self.tabBar.items else {
            return
        }
        for item in items {
            item.title = ""
            item.imageInsets = UIEdgeInsets(top: 6, left: 0, bottom: -6, right: 0)
        }
    }
}

And you just need to call self.tabBarController?.cleanTitles() in your view controller.


E
Egzon P.

Custom TabBar - iOS 13, Swift 5, XCode 11

TabBar items without text

TabBar items centered vertically

Rounded TabBar view

TabBar Dynamic position and frames

Storyboard based. It can be achieved easily programmatically too. Only 4 Steps to follow:

Tab Bar Icons must be in 3 sizes, in black color. Usually, I download from fa2png.io - sizes: 25x25, 50x50, 75x75. PDF image files do not work! In Storyboard for the tab bar item set the icon you want to use through Attributes Inspector. (see screenshot)

https://i.stack.imgur.com/qfEjV.png

Custom TabBarController -> New File -> Type: UITabBarController -> Set on storyboard. (see screenshot)

https://i.stack.imgur.com/bNyo9.png

UITabBarController class class RoundedTabBarViewController: UITabBarController { override func viewDidLoad() { super.viewDidLoad() // Do any additional setup after loading the view. // Custom tab bar view customizeTabBarView() } private func customizeTabBarView() { let tabBarHeight = tabBar.frame.size.height self.tabBar.layer.masksToBounds = true self.tabBar.isTranslucent = true self.tabBar.barStyle = .default self.tabBar.layer.cornerRadius = tabBarHeight/2 self.tabBar.layer.maskedCorners = [.layerMaxXMaxYCorner, .layerMaxXMinYCorner, .layerMinXMaxYCorner, .layerMinXMinYCorner] } override func viewDidLayoutSubviews() { super.viewDidLayoutSubviews() let viewWidth = self.view.bounds.width let leadingTrailingSpace = viewWidth * 0.05 tabBar.frame = CGRect(x: leadingTrailingSpace, y: 200, width: viewWidth - (2 * leadingTrailingSpace), height: 49) } } Result


G
Giang

https://i.stack.imgur.com/tAVFY.png

code:

private func removeText() {
    if let items = yourTabBarVC?.tabBar.items {
       for item in items {
          item.title = ""
       }
    }
 }

C
Chintan Shah

In my case, same ViewController was used in TabBar and other navigation flow. Inside my ViewController, I have set self.title = "Some Title" which was appearing in TabBar regardless of setting title nil or blank while adding it in tab bar. I have also set imageInsets as follow:

item.imageInsets = UIEdgeInsets(top: 6, left: 0, bottom: -6, right: 0)

So inside my ViewController, I have handled navigation title as follow:

if isFromTabBar {
   // Title for NavigationBar when ViewController is added in TabBar
   // NOTE: Do not set self.title = "Some Title" here as it will set title of tabBarItem
   self.navigationItem.title = "Some Title"
} else {
   // Title for NavigationBar when ViewController is opened from navigation flow
   self.title = "Some Title"
}

E
Eric Aya

Based on all the great answers on this page, I've crafted another solution that also allows you to show the the title again. Instead of removing the content of title, I just change the font color to transparent.

extension UITabBarItem {

    func setTitleColorFor(normalState: UIColor, selectedState: UIColor) {
        self.setTitleTextAttributes([NSAttributedString.Key.foregroundColor: normalState], for: .normal)
        self.setTitleTextAttributes([NSAttributedString.Key.foregroundColor: selectedState], for: .selected)
    }

}


extension UITabBarController {

    func hideItemsTitle() {

        guard let items = self.tabBar.items else {
            return
        }

        for item in items {
            item.setTitleColorFor(normalState: UIColor(white: 0, alpha: 0), selectedState: UIColor(white: 0, alpha: 0))
            item.imageInsets = UIEdgeInsets(top: 6, left: 0, bottom: -6, right: 0)
        }

    }

    func showItemsTitle() {

        guard let items = self.tabBar.items else {
            return
        }

        for item in items {
            item.setTitleColorFor(normalState: .black, selectedState: .yellow)
            item.imageInsets = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)
        }

    }

}

J
JulianKro

Easiest way and always works:

class TabBar: UITabBar {

    override func layoutSubviews() {
        super.layoutSubviews()

        subviews.forEach { subview in
            if subview is UIControl {
                subview.subviews.forEach {
                    if $0 is UILabel {
                        $0.isHidden = true
                        subview.frame.origin.y = $0.frame.height / 2.0
                    }
                }
            }
        }
    }
}

s
soheil pakgohar

make a subclass of UITabBarController and assign that to your tabBar , then in the viewDidLoad method place this line of code:

tabBar.items?.forEach({ (item) in
        item.imageInsets = UIEdgeInsets.init(top: 8, left: 0, bottom: -8, right: 0)
    })

C
Campbell_Souped

If you are looking to center the tabs / change the image insets without using magic numbers, the following has worked for me (in Swift 5.2.2):

In a UITabBarController subclass, you can add add the image insets after setting the view controllers.

override var viewControllers: [UIViewController]? {
    didSet {
      addImageInsets()
    }
}

func addImageInsets() {
    let tabBarHeight = tabBar.frame.height

    for item in tabBar.items ?? [] where item.image != nil {
      let imageHeight = item.image?.size.height ?? 0
      let inset = CGFloat(Int((tabBarHeight - imageHeight) / 4))
      item.imageInsets = UIEdgeInsets(top: inset,
                                      left: 0,
                                      bottom: -inset,
                                      right: 0)
    }
}

Several of the options above list solutions for dealing with hiding the text.