在iOS7上,如何更改一个UITabBarItem的背景颜色?

7

我可以改变UITabBar中特定UITabBarItem的背景颜色吗?

我知道如何改变所有选中背景的背景,使用以下代码:

[[UITabBar appearance] setBarTintColor:[UIColor redColor]];
[[UITabBar appearance] setTintColor:[UIColor blueColor]];
[[UITabBar appearance] setSelectedImageTintColor:[UIColor yellowColor]];

但是能否不使用子类来仅对一个项目进行此操作呢?

谢谢

6个回答

33
您可以将子视图添加到父 tabBar 上,并在子视图上设置背景颜色。您可以使用 tabBar 的框架尺寸来计算选项卡项目的偏移量和宽度,然后将子视图插入其中。
示例(使用 Swift):
// Add background color to middle tabBarItem
let itemIndex = 2
let bgColor = UIColor(red: 0.08, green: 0.726, blue: 0.702, alpha: 1.0)

let itemWidth = tabBar.frame.width / CGFloat(tabBar.items!.count)
let bgView = UIView(frame: CGRectMake(itemWidth * itemIndex, 0, itemWidth, tabBar.frame.height))
bgView.backgroundColor = bgColor
tabBar.insertSubview(bgView, atIndex: 0)

谢谢@nathan.f77,它起作用了,唯一的问题是它只允许我更改背景颜色(我接受了你的答案,因为那实际上是我的问题)。但是当我改变背景颜色时,我还需要改变此项的色调...目前,我在tarBar顶部添加了一个按钮来代替该项... :( - Hugues BR
当我复制并粘贴这段代码时,xCode会在以下行上报错:“let bgView = ...”,错误信息为“找不到成员框架”。 - Chris Harrison
@ChrisHarrison - 这很奇怪,因为你在上一行中调用了 tabBar.frame,所以那里也应该出现错误。 - ndbroadbent
@nathan.f77 更改为以下代码:let itemWidth: CGFloat = tabBar.frame.width / CGFloat(tabBar.items!.count)可以解决这个问题。 - Chris Harrison
这真的很聪明。我以为insertSubview:会阻止图标和文本。结果并没有。 - Di Wu

6

在Swift中: 这个解决方案适用于使用Auto Layout的应用程序。与其他解决方案的主要区别在于:tabBar.frame.width没有获取实际设备屏幕宽度。因此,bgView会显示在错误的位置。

您可以通过以下方法修复它:UIScreen.main.bounds.width

let tabWidth: CGFloat = UIScreen.main.bounds.width / CGFloat(self.tabbar!.items!.count)
let tabIndex: CGFloat = 2
let bgColor: UIColor = .redColor
let bgView = UIView(frame: CGRectMake(tabWidth * tabIndex, 0, tabWidth, 49))
bgView.backgroundColor = bgColor
self.tabbar!.insertSubview(bgView, atIndex: 0)

UITabbar的默认高度是49。


不确定这是否是由于最近对自动布局的更改引起的,但这将无法工作。在最后一行代码中将新视图插入索引0将使其他子视图(很可能是背景视图)覆盖我们的新视图。与所有视图定义一样,子视图的顺序对于渲染很重要。为了将新视图放置在背景视图上方但在tabIndex项的图像和文本下方,这似乎可以通过iOS 9 / Xcode 7.3修复:self.tabBar!.insertSubview(bgView,在tabIndex + 2处) - marco
太好了!谢谢!我确认它可以在iOS 12.1和Xcode 10.1上运行。 - iHarshil

3

Objective C解决方案:

int itemIndex = 3;
UIColor* bgColor = [UIColor colorWithRed:(245/255.f) green:(192/255.f) blue:(47/255.f) alpha:1];

float itemWidth = self.tabBarController.tabBar.frame.size.width / 5.0f; //5 = tab bar items
UIView* bgView = [[UIView alloc]initWithFrame: CGRectMake(itemWidth*itemIndex, 0,itemWidth, self.tabBarController.tabBar.frame.size.height)];
bgView.backgroundColor = bgColor;
[self.tabBarController.tabBar insertSubview:bgView atIndex:1];

1

更新至 Swift 4:

let itemIndex: CGFloat = 2.0
let bgColor = UIColor.ownBlue

let itemWidth = tabBar.frame.width / CGFloat(tabBar.items!.count)
let bgView = UIView(frame: CGRect(x: itemWidth * itemIndex, y: 0, width: itemWidth, height: tabBar.frame.height))

bgView.backgroundColor = bgColor
tabBar.insertSubview(bgView, at: 0)

0
有点晚了,但这是我实现的方式。我将选项卡看起来像按钮,带圆形视图。以上的答案,在设备旋转或应用程序进入分割窗口时存在问题。
这个解决方案直接将背景与每个选项卡结合起来,使用自动布局,使它们自然地跟随选项卡栏的变化。
这是在UITabBarController的自定义子类上完成的。
首先,我设置选项卡项目中图标的颜色(未选择的为白色,选择的为黑色),然后我迭代选项卡,并向每个选项卡插入背景,使用自动布局让它们贴合选项卡:
override func viewDidLoad() {
    super.viewDidLoad()
    let appearance = UITabBarAppearance()
    appearance.stackedLayoutAppearance.normal.iconColor = .white
    appearance.stackedLayoutAppearance.selected.iconColor = .black
    appearance.inlineLayoutAppearance.normal.iconColor = .white
    appearance.inlineLayoutAppearance.selected.iconColor = .black
    appearance.compactInlineLayoutAppearance.normal.iconColor = .white
    appearance.compactInlineLayoutAppearance.selected.iconColor = .black

    tabBar.subviews.forEach {
        if let item = $0 as? UIControl {
            let wrapper = UIView()
            wrapper.isUserInteractionEnabled = false
            wrapper.clipsToBounds = true
            wrapper.backgroundColor = tabBar.tintColor
            wrapper.layer.cornerRadius = 8
            item.insertSubview(wrapper, at: 0)
            wrapper.translatesAutoresizingMaskIntoConstraints = false
            wrapper.leadingAnchor.constraint(equalTo: item.leadingAnchor).isActive = true
            wrapper.trailingAnchor.constraint(equalTo: item.trailingAnchor).isActive = true
            wrapper.topAnchor.constraint(equalTo: item.topAnchor).isActive = true
            wrapper.bottomAnchor.constraint(equalTo: item.bottomAnchor).isActive = true
        }
    }
}

这个方法有效的原因是,选项卡栏将选项卡项实现为UIControl的内部子类,而UIControl又是UIView的子类。

我可以在控件下面添加视图。

最终效果如下:

Sample Tab Bar

注意:关闭用户交互是很重要的,插入到0也是。

缺点是没有办法知道哪个项目是被选中的(在背景图像创建时)。

还要注意:苹果真的不希望我们在标签栏里瞎搞,我可以想象这种方法(以及上面的方法)在一些未来的操作系统升级中会失效。


0

你不能通过 tint color 属性来实现这个。请参见此文章,关于即使是 setSelectedImageTintColor 看起来似乎并没有真正起作用(上一次我检查时确实如此)。

解决方案是在需要的项目中动态更改 tintColor。每当选择的项目更改时,你可以使用 ad hoc 方法通过实现 app delegate 中的 UITabBarDelegate 方法 tabBar:didSelectItem: 来实现这一点。


嘿@Mundi,谢谢你的回答。我不想在选择时更改它,而是一直保持不变。基本上,我有五个按钮,除了中间那个带黑色背景的按钮外,其他都是白色背景。 - Hugues BR
@HuguesBR,你找到解决方法了吗? - knl
不是真的,我已经在选项卡栏视图中添加了一个UIButton,它遮盖了相关的选项卡以达到效果... - Hugues BR

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接